在去年的Google大會中,Google官方推出了新的開發元件:Lifecycle和LiveData。Lifecycle是監聽資料生命周期變化的,這裡不再贅述。我們來主要說說LiveData的應用,LiveData預設實作了LifecycleObserver接口,是以它是一個生命周期感覺元件。觀察者可以指定某一個Lifecycle給LiveData,并對資料進行監聽。在Lifecycle穩定之後,Activity和Fragment都預設是LifecycleOwner,是以可以直接添加觀察者。應用LiveData可以進行MVVM模式的開發,實作資料類似VUE中的雙向綁定,這其實是很不錯的。好了,話不多說,直接上代碼吧。
這裡我們先建立一個Project實體類(Model):
class Project {
var boid: String? = null
var type: String? = null
var title: String? = null
}
接下來就是ViewModel的編寫了:
class ProjectViewModel<T> : ViewModel(){
private var url = ""
var project: LiveData<T>? = null
fun init(url: String) {
this.url = url
}
}
在這裡我們使用了泛型,這是為實作通用的ViewModel做準備。畢竟在工程中,重複的代碼我們是不想寫很多的遍的吧。
好了,到這裡ViewModel就已經建立起來了,現在我們在Activity中來進行應用監聽。
val url = "你的接口位址"
viewModel = ViewModelProviders.of(this).get(ProjectViewModel<Project>()::class.java)
viewModel!!.init(url)
viewModel!!.project!!.observe(this, Observer<Project> {
//這裡來重新整理UI
})
ViewModel.project.observe看這句的代碼的源碼,你會發現這其實就是在添加觀察者:
owner.getLifecycle().addObserver(wrapper);
上面我們提到了Activity和Fragment在Liftcycle穩定之後會預設是LiftcycleOwner這裡得到了很好的展現。那麼,現在萬事俱備,隻欠東風了。資料從哪裡來呢?這個時候就需要一個專門來處理資料的類了。當然,你也可以把處理資料的子產品直接放在ViewModel中進行,但是我不推薦你那樣做。畢竟我們寫代碼還是要有逼格的對嗎,能分的細緻一點就分的細緻一點,這樣寫出來的代碼才優雅。
好了,現在我們來建立一個ProjectRepository類來處理資料:
class ProjectRepository<T> {
public fun<T> getProject(url:String):LiveData<T>{
val item = Project()
val data = MutableLiveData<T>()
doAsync {
val jsonStr = URL(url).readText()
try {
//TODO 這裡來處理從接口擷取的資料
uiThread {
//liveData實作了類似VUE中的資料雙向綁定的概念,每次data中的value發生改變都會觸發觀察者向UI線程發送消息來重新整理UI
data.value = item as T
item.title = "德瑪西亞"
data.value = item
}
}catch (e:Exception){
e.printStackTrace()
}
}
return data
}
}
可以看到這裡我們是從背景服務上擷取的資料,并且運用的是anko中的方法。你也可以用你自己喜歡的方式來和伺服器進行互動(okhttp,Retrofit等)。這樣将資料擷取分開來寫還有一個好處就是當資料擷取方式發生改變的時候可以直接改變擷取方式就好了,簡介明了,避免出現GOD CLASS。在代碼的末尾處我們又人為的改變了title值,這是用來驗證資料變化監聽的。現在資料來源也有了,我們要把ProjectRepository和ProjectViewModel連接配接起來了:
class ProjectViewModel<T> : ViewModel() {
private var url = ""
var project: LiveData<T>? = null
val Repo = ProjectRepository<T>()
fun init(url: String) {
this.url = url
project = Repo.getProject(url)
}
}
這裡init就是提供一個類似鑰匙的作用。如果你的資料不是從伺服器擷取而是從本地資料庫擷取。那麼這裡的init的參數就有可能是一個查詢的條件值了。好了到這裡為止,一個簡單的LiveData運用就寫完了。