以注重生命週期的方式管理和界面相關的數據,Jetpack爲咱們帶來了ViewModel,從本文你能夠學習到使用ViewModel的正確姿式。java
ViewModel被用來以注重生命週期的方式來保存數據和管理界面相關的數據。同時能夠在相關配置發生變化是保存數據,例如屏幕旋轉。android
因爲Android framework管理着像Activity、Fragment這樣具備生命週期的UI控制器,因此在用戶的某些操做或者系統分發的某些事件,會致使framework在沒有通過咱們控制下,銷燬和重建UI控制器。例如,屏幕發生旋轉時,framwork會調用Activity的onSaveIntanceState()
保存數據,在新Activity的onCreate()
方法中恢復這些數據,不過這僅僅是恢復可序列化和反序列化的小數據上,像list或者bitmap這種大數據就不合適了。此外,也會致使大量已經存在的數據被銷燬,而後從新生成,形成資源的浪費。git
在LiveData
也說到,不要在Activity和Fragment作大量的邏輯操做,會致使代碼臃腫,難以維護,建議把相關邏輯抽到單獨的類進行維護,讓UI控制器負責它們的本質工做。github
爲此,使用ViewModel能夠輕鬆解決以上問題。數據庫
Architecture Components提供ViewModel工具類,用來爲UI提供數據。ViewModel對象在配置發生變化時會自動保存數據,而且會在新建的Activity或Fragment實例使用。例如,在APP中須要顯示持有多個user對象的list,應該將請求和保存users數據的動做在ViewModel對象實現,而不是Activity或Fragment。api
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
複製代碼
在Activity中訪問數據:bash
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity’s onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI
})
}
}
複製代碼
當Activity被重建時,它會接收到來自第一個Activity的ViewModel對象,因此數據不會發生變化。當Activity銷燬後,framework會自動調用ViewModel對象的onCleared()
方法來進行釋放資源。記得,ViewModel必定不要持有View、Lifecycle或者任何有Activity context對象的引用。由於ViewModel的生命週期比它們的長,會致使內存泄漏。若是ViewModel須要持有應用的conetxt,例如用來獲取系統服務,能夠繼承AndroidViewModel類,在它的構造方法中對接收應用的context。架構
若是Android Studio找不到ViewModelProviders,添加下面依賴哦。async
api "android.arch.lifecycle:extensions:1.1.1"
複製代碼
ViewModelProvider獲取ViewModel對象時,ViewModel的生命週期做用域會傳遞給ViewModelProvider,ViewModel會一直保持在內存中,直到其生命週期做用域失效。在下面兩種狀況,ViewModel對象生命週期會失效:一種是Activity對象finished,一種是Fragment對象detached。ide
下圖(圖來自官網)顯示了Activity的生命週期和ViewModel的做用域,第一列顯示了Activity對象的狀態,第二列顯示Activity生命週期方法,第三列ViewModel的做用域。
onCreate()
方法,咱們一般要在第一次時間建立ViewModel對象。在Activity對象的生命週期內,
onCreate()
方法可能因爲系統配置改變而被系統調用屢次,而ViewModel對象只有一次,ViewModel對象會一直存在直到Activity被終結和銷燬掉。
在實際開發中,常常會在兩個或多個fragement對象共享數據,一般作法是實定義接口,由Activity綁定在fragment中。此外,Activity還要處理fragment的建立和可見的狀況。
fragment之間能夠在Activity的做用域內共享同個ViewModel對象來處理這個麻煩的數據交互問題。例如:
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
class DetailFragment : Fragment() {
private lateinit var model: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = activity?.run {
ViewModelProviders.of(this).get(SharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
model.selected.observe(this, Observer<Item> { item ->
// Update the UI
})
}
}
複製代碼
因爲兩個Fragment對象綁定在同一個Activity對象,它們經過ViewModelProvider獲取在Activity範圍內的同一個ViewModel對象。
這樣作的好處是:
加載器類像CursorLoader,常常用來保持UI中的數據與數據庫的同步。能夠經過ViewModel,和其餘的類,替換Loader類。使用ViewModel分離UI控制器的數據加載動做,意味着能夠減小更多的類強引用。 使用Loader一個常見的方法,就是在應用程序中使用一個CursorLoader觀察的數據庫內容,當數據庫的值發生變化時,Loader自動從新加載數據和更新用戶界面:
Jetpack講到這裏,基本都明白Jetpack是幹嗎了,Jetpack總結咱們日常開發的各類效率和架構,爲咱們提供更標準的組件。Room操做數據庫,LiveData通知數據更改,DataBinding更新View,Lifecycle管理週期,及其後面要講的其餘組件。都在給咱們應用層開發定義一套統一開發架構標準,以即可以開發更好APP。經過這麼一套架構組件,能夠快速開發可維護性高,擴展性好的APP。
本文是Jetpack系列文章第四篇