LiveData 是一種可觀察的數據存儲器類。與常規的可觀察類不同,LiveData 具有生命周期感知能力,意指它遵循其他應用組件(如 activity、fragment 或 service)的生命周期。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態的應用組件觀察者。
若觀察者(Observer)的生命周期處于STARTED或RESUMED狀態,則LiveData會認為該Observer處于活躍狀態。LiveData只會將更新通知給活躍的Observer。
您可以注冊與實現?LifecycleOwner?接口的對象配對的觀察者。有了這種關系,當相應的?Lifecycle?對象的狀態變為?DESTROYED?時,便可移除此觀察者。這對于 activity 和 fragment 特別有用,因為它們可以放心地觀察?LiveData?對象,而不必擔心泄露(當 activity 和 fragment 的生命周期被銷毀時,系統會立即退訂它們)。
使用LiveData的優勢
確保界面符合數據狀態:LiveData遵循觀察者模式。當底層數據發生變化,LiveData會通知Observer對象,此時我們可以寫入邏輯,以在Observer中更新界面。這樣一來,我們就不用每次在數據發生變化時更新界面,因為Observer會完成這一內容;
不會發生內存泄漏:Observer綁定到LifeCycle對象,并在其關聯的生命周期結束后自動清理,這一點與ViewModel類似;
不會因為Activity停止而導致崩潰:若Observer的生命周期處于非活躍狀態(如返回對戰的activity),它就不會接受LiveData事件;
不需要手動處理生命周期:界面組件只是觀察相關數據,不會停止或恢復觀察。LiveData 將自動管理所有這些操作,因為它在觀察時可以感知相關的生命周期狀態變化;
使用LiveData對象
當更新存儲在LiveData對象中的值時,它會觸發所有已注冊的Observer(只要它所附加的Life cycleOwner處于活躍狀態)。
創建
LiveData對象通常存儲在ViewModel對象中,并可以使用getter方法訪問:
class NameViewModel : ViewModel() {// LiveData可用于任何類型的數據,此處創建一個String類型的LiveData對象val currentName: MutableLiveData<String> by lazy {//使用lazy懶加載,當需要使用再創建MutableLiveData<String>()}// ViewModel的剩余部分...
}
存儲在ViewModel中、而不是activity或fragment的原因是:
- 避免activity和fragment過于龐大。我們使用MVVM架構的原因之一,就是為了使這些界面控制器只負責顯示數據,而不存儲數據;
- 將LiveData實例與特定的activity或fragment實例分離開,使得LiveData對象在配置更改后仍然存在。
觀察
大多數時候,從組件onCreate方法中開始觀察LiveData對象,以確保系統不會從onResume方法中進行冗余調用,并確保activity或fragment變為活躍狀態后具有可以立即顯示的數據。一旦組件處于STARTED狀態,就會從它觀察的LiveData接受最新的值。
另外,除了LiveData在發生數據更改時會發送更新,Observer從非活躍狀態變為活躍狀態時也會收到更新。但是,如果Observer第二次發生這樣的狀態改變,則只有上次的改變會收到更新。
class NameActivity : AppCompatActivity() {private val model: NameViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化activity的內容...// 創建觀察ui更新的observerval nameObserver = Observer<String> { newName ->// 更新ui,此處是一個TextViewnameTextView.text = newName}// 觀察LiveData, 將此activity作為LifecycleOwner和observermodel.currentName.observe(this, nameObserver)}
}
我們也可以簡寫這一部份:
class NameActivity : AppCompatActivity() {private val model: NameViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 其他初始化activity的內容...// 簡寫nameTextView.text = model.currentName.observeAsState()}
}
在傳遞nameObserver參數的情況下調用observe方法后,系統會立即調用onChanged方法,從而提供mCurrentName中存儲的最新值。若LiveData對象上為在mCurrentName中設置值,系統不會調用onChanged方法。
更新
LiveData沒有公開可用的方法來更新存儲的數據。如果需要修改存儲在LiveData對象中的值,需要重寫MutableLiveData中的setValue方法或postValue方法。
通常情況下會在ViewModel中使用MutableLiveData,然后ViewModel只會向觀察者公開不可變的LiveData對象。設置觀察者關系之后,我們就可以更新LiveData對象的值:
button.setOnClickListener {val anotherName = "John Doe"model.currentName.setValue(anotherName)
}
在主線程中我們使用setValue方法更新數據,而在工作器線程中,我們可以改用postValue方法來更新Livedata對象。
擴展LiveData?
如果觀察者的生命周期處于STARTED或RESUMED狀態,則LiveData會認為該觀察者處于活躍狀態,以下是擴展LiveData類的例子:
//價格監聽器
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {private val stockManager = StockManager(symbol)private val listener = { price: BigDecimal ->value = price}//當LiveData對象具有活躍觀察者時,會調用此方法override fun onActive() {//從此方法開始觀察股價更新stockManager.requestPriceUpdates(listener)}//當LiveData對象沒有活躍觀察者時,會調用此方法override fun onInactive() {//斷開StockManager服務stockManager.removeUpdates(listener)}
}
接下來我們使用重寫后的StockLiveData類:
public class MyFragment : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)val myPriceListener: LiveData<BigDecimal> = ...myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->// Update the UI.})}
}
組件如activity、fragment在初始化時構建了自己的LifecycleOwener。此處的observe方法將與Fragment視圖關聯的LifecycleOwner作為第一個參數傳遞,這樣做表示此觀察者已綁定到與其所有者關聯的Lifecycle對象(即組件,在此處是MyFragment),這意味著;
- 如果Lifecycle對象未處于活躍狀態,即使值發生更改,也不會調用觀察者;
- 銷毀Lifecycle對象后,會自動移除觀察者。
同時LiveData對象具有生命周期感知能力,意味著我們可以在多個activity、fragment和service之間共享這些對象。
我們也可以將StockLiveData實現為一個單例(companion object):
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {private val stockManager: StockManager = StockManager(symbol)private val listener = { price: BigDecimal ->value = price}override fun onActive() {stockManager.requestPriceUpdates(listener)}override fun onInactive() {stockManager.removeUpdates(listener)}companion object {private lateinit var sInstance: StockLiveData@MainThreadfun get(symbol: String): StockLiveData {sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)return sInstance}}
}
為什么使用了單例?以StockLiveData為例,單例的好處是在使用時不需要再創建一個StockLiveData的實例,而是直接引用它的方法:
class MyFragment : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->// Update the UI.})}