LiveData 原理解析

2019-10-27  本文已影响0人  毒死预言家的女巫

提纲

一、什么是 LiveData

LiveData 是一个可以被观察的数据持有类,它可以感知 Activity、Fragment或Service 等Android组件的生命周期。这意味着一个LiveData的观察者可以和一个生命周期的持有者绑定在一起,并且只有在对应的生命周期持有者的状态是Active的时候,LiveData才会通知观察者。

二、LiveData的优点

三、一个实际需求

在开发一款实时通讯录软件的过程中,我遇到了这样的一个需求:
在实现通讯录模块时,联系人数据源使用了持久化存储——List<Contact>。若我们希望在对联系人列表进行增删改后,更改数据源的同时,数据的更新可以实时的显示在联系人页面上。如果我们仅在每次进入联系人页面时进行一次数据渲染,就不能达到实时更新的效果。

怎么解决这个问题呢?那就是在每一次数据源更新的时候,重新获取数据,用最新的数据渲染。

四、观察者模式

既然在每一次的数据源变化都要重新进行渲染,我们不难想到使用观察者模式来解决这个问题。
这是一个简单的观察者模式的UML图,其中我们声明了Subject<T>是我们要进行观察的对象类,而Observer则是观察者的抽象接口,在我们的Activtiy中的内部类ObserverImpl类具体实现了onChange()方法。其中被观察的对象Subject持有一个观察者Obsever们的列表,每当调用setData()方法的时候,遍历所有的观察者们,通知他们调用onchange()方法。

观察者模式

在实际的需求中,我们可以声明一个全局的 Subject<List<Contact>> 作为被观察者,在展示数据的Activity中实现一个ObserverImpl类,在onchange()方法中写上通过数据源渲染页面的逻辑,并将其注册到Subject中。这样每次更改数据源时,调用SubjectsetData()方法,就会调用ObserverImpl的onChange()方法进行实时更新。

问题看似得到了解决。

五、LiveData —— 一个 Android Specific 的观察者模式

在讲LiveData的原理之前,我们先来铺垫一些Android生命周期的知识——

用户触发不同的事件,会使Activity经历不同的生命周期,从而体现出不同的状态
Acitivity一般意义上有四种状态:

  1. 当Activity处于屏幕最前方,此时是运行状态(Running)。
  2. 当Activity失去了焦点但仍然对用户可见,此时处于暂停状态(pause)。
  3. 当Activity被其他Activity完全遮挡,此时此Activity对用户不可见,此时处于停止状态(Stopped)
  4. 当Activity由于人为或系统原因(如低内存等)被销毁,此时处于销毁状态(Killed)。


    Android Activity生命周期及其状态

然后我们再来看看之前我们的观察者模式出了什么问题:

问题在于第四种状态——销毁状态,这时会把Activity句柄设置为null来释放内存。但是此时Activity还是被Subject所持有,Subject对象是必须在应用生命周期的全过程都存在的。虽然当Activity的生命周期已经结束并设置为null,但Activity实例对象在堆中的内存并不会释放,这样就造成了内存泄露。

内存泄露

还有一个可以优化的地方是,只有在第一、二种状态时,Activity才是可见的,且处于这种状态的Activity在大部分时间都是最少数的。在处于第三种状态时,Activity处于后台并不可见。在不可见的状态是不需要进行UI上的更新的,只要在Activity从不可见状态更新到可见状态以后通知一遍观察者就足够了。

LiveData 的解决方案:
如果我们要使用Live Data,我们一定要使用实现了LifeCycleOwner接口的组件(如AppCompatActivity),实现了这个接口的组件可以向外提供自己的所在生命周期的状态,在注册LiveData的观察者时,将Observer和Activity绑定传入。这样LiveData就可以感知生命周期的变化,自动的解绑、并只通知可见的Activity进行变化,并且在activity从不可见到可见的状态后通知观察。

LiveData UML图

六、LiveData的使用:

在通讯录需求中,我们的联系人数据需要全局使用,所以声明一个全局的LiveData对象。LiveData的setData()方法是protected的,如果想使用这个setData()方法,我们可以使用MutableLiveData或者自己继承LiveData定制。

object ContactsLiveData : LiveData<List<ContactBean>> {

    fun add(contactBean : ContactBean){
        val list = Preference.contact.toMutableList()//获取缓存列表
        list.add(contactBean)
        Preference.contacts = list//更新缓存
        setValue(list)//调用LiveData的setValue()。
    }
    
    fun remove() = //...

}

然后在Activity中的onCreate方法注册

ContactsLiveData.observe(this, Observer{ it ->
    val list = ContactsLiveData.value.asSequence()
        .sortedBy{ Selector(it.name) }
        .toList()
    rec_contact.withItems{
    var oldChar = ';'
    list.forEach {
        var newChar = FirstLetterUtil.getFirstLetter(it.name)[0]
        if (oldChar!=newChar) {
              contact(mActivity,it,newChar,true)
              oldChar = newChar
        } else {
              contact(mActivity,it,newChar,false)
        }
    }
 }
 })
上一篇 下一篇

猜你喜欢

热点阅读