MVVM是近年在Android開發中比較熱門的設計模式,這是因為google在2017年推出Architechture Component把MVVM的設計模式包裝在SDK裡也使得這一兩年在Android平台開發的使用率大幅上升,我們先來看一段MVVM的實作介紹,如果你對MVVM己經很熟想直接看結論可以直接跳到最後一段。
class MvvmActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mvvm)
val model = ViewModelProviders.of(this)[MyViewModel::class.java]
model.apiManager = ServerApi()
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI
})
}
}
class ServerApi {
fun requestUser(): List<User>? {
//implement remote connection
return null
}
}
class MyViewModel : ViewModel() {
var apiManager: ServerApi? = null
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData<List<User>>().also {
val list = loadUsers()?.filter { it.firstName == "Daniel" }
it.postValue(list)
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers(): List<User>? {
return apiManager?.requestUser()
}
}
上面程式碼範例,假設我們有一個MvvmActivity,MvvmActivity在onCreate()的時候就要跟Server要求User資料來顯示,所以我們有一個ServerApi的class在處理reqeust流程,然後在ServerApi裡面有個requestUser()的function會回傳User清單。然後我們創建一個MyViewModel的class去處理跟Server request後的資料。ViewModel要實作Android SDK提供的ViewModel介面之後我們就可以在Activity裡面利用ViewModelProvider來把我們自定的MyViewModel實體化出來使用,這時候我們就可以監聽ViewModel裡的Observer變數。而範例裡要被Activity觀察的變數是users,一但users有改變就通知Activity來做後續update UI的行為。
那users怎麼寫成觀察者模式的變數?這點Android SDK已經幫我們做完了,你也可以選擇自己做但是我不建議,我們只需要把users變數宣告成SDK內建的LiveData類別就可以使用ViewModel的觀察者模式了。而LiveData不僅僅只是實作observer而已,它還有強大的Android lifecycle aware的作用,可以防止Android常見的Activity memory leak。
範例中users這個LiveData會從private function loadUsers()去跟Server 去詢問資料再由reqeustUsers()中得到的資料,這裡用Kotlin的filter function去選擇firstName叫Daniel的user,最後用LiveData postValue的方法通知Activity的觀察者ViewModel已經改變,請同時update UI。
記得我在MVP的章節有講過在Presenter裡面我們會用constructor或是setter的方式注入view interface來呼叫抽象的function,好讓presenter跟activity溝通。雖然我們控制的是View的interface但帶入的其實是Activity的實體,而在Application實作當中我們常常會把非同步的task邏輯如server api reqeust,database或image processing等等放在presenter裡面來使用,當user在callback還沒回來前就先destroy Activity了(可能是主動back或被系統回收等等狀況),就會造成presenter所參照的reference消失了而導致applicaton crash。MVVM模式的出現剛好可以解決這個問題。
MVVM跟MPV不一樣的地方是MVVM用觀察者模式(Observer pattern)來替代Activity UI實體的抽象化,也就是原本在Presenter內被參考的Activity實體被換成ViewModel裡的觀察者物件,再從Activity內去listen這個觀察者物件的行為。利用這個方式我們就不用把Activity的reference放到Presenter裡去呼叫,也就是View跟ViewModel之間的關係被解耦。在MVP模式裡Presenter跟View並沒有解耦,對做單元測試上的好處相同的是它們把邏輯分開在另一個地方(Presenter & ViewModel)可以方便我們做單元測試。
關於MVVM測試程式的部份會在下一章節說明。