Android的LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者

若观察者(Observer)的生命周期处于STARTEDRESUMED状态,则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更新的observer
        val nameObserver = Observer<String> { newName ->
            // 更新ui,此处是一个TextView
            nameTextView.text = newName
        }

        // 观察LiveData, 将此activity作为LifecycleOwner和observer
        model.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

        @MainThread
        fun 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.
        })

    }
  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值