提纲
- 什么是LiveData
- 为什么要用LiveData
- 一个实际需求
- 观察者模式
- LiveData —— 一个 Android Specific 的观察者模式
- LiveData 的使用
一、什么是 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
中。这样每次更改数据源时,调用Subject
的setData()
方法,就会调用ObserverImpl的onChange()
方法进行实时更新。
问题看似得到了解决。
五、LiveData —— 一个 Android Specific 的观察者模式
在讲LiveData的原理之前,我们先来铺垫一些Android生命周期的知识——
用户触发不同的事件,会使Activity经历不同的生命周期,从而体现出不同的状态
Acitivity一般意义上有四种状态:
- 当Activity处于屏幕最前方,此时是运行状态(Running)。
- 当Activity失去了焦点但仍然对用户可见,此时处于暂停状态(pause)。
- 当Activity被其他Activity完全遮挡,此时此Activity对用户不可见,此时处于停止状态(Stopped)
-
当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的使用:
在通讯录需求中,我们的联系人数据需要全局使用,所以声明一个全局的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)
}
}
}
})
网友评论