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.})}