如果你看过了Android架构组件之Lifecycle,可以立马投入到LiveData
组件的学习中,同样的,LiveData
也是Google I/O
大会上发布的架构组件,ListData
是一个可被观察的数据持有类,为我们什么需要使用LiveData
?主要有以下几个有点:
更多参考
一,保证数据与界面的实时更新
LiveData
采用了观察者模式设计,其中LiveData
是被观察者,当数据发生变化时会通知观察者进行数据更新。通过这点,可以确保数据和界面的实时性。
二,有效避免内存泄漏
这是因为LiveData
能够感知到组件的生命周期,当组件状态处于DESTROYED
状态时,观察者对象会被remove
。
三,Activity/Fragment
销毁掉时不会引起崩溃
这是因为组件处于非激活状态时,在界面不会收到来自LiveData
的数据变化通知。这样规避了很多因为页面销毁之后,修改UI导致的crash
。
四,不需要手动处理生命周期
LiveData
能够感知组件的生命周期,所以设置LiveData
组件的生命周期状态。
五,始终能够保持最新数据
生命周期从非活跃状态切换到活跃状态的时候,能够实时的接收最新的数据。
六,能够应对配置更改
由于LiveData
保存数据的时候,组件和数据是分离的,所以在配置更改(如横竖屏切换等)的时候,即便组件被重新创建,因为数据还保存在LiveData
中,这样也能够做到实时的更新。
七,资源共享
单例模式扩展LiveData
对象并包装成系统服务,以便在应用程序中进行共享,需要该资源的只需要观察LiveData
即可。
LiveData的使用
通常使用LiveData
有三个步骤:
1,创建LiveData
实例来保存数据,常常是配合ViewModel
一起工作;
2,定义一个Observer
的观察者对象,如果有数据更新会通过观察者的onChanged()
方法来同步到UI
上面;
3,将观察者Observer
通过observe()
方法进行绑定。
LiveData
有两种使用方法:一种是直接使用,如接下来的例子;还有一种是继承LiveData
的实现资源共享的方式。
直接使用的时候,LiveData
一般和ViewModel
一起使用。
首先定义个MyNameViewModel
类
class MyNameViewModel : ViewModel() {
// Create a LiveData with a String
private var mCurrentName: MutableLiveData<String>? = null
// Create a LiveData with a String list
private var mNameListData: MutableLiveData<List<String>>? = null
open fun currentName(): MutableLiveData<String> {
if (mCurrentName == null) {
mCurrentName = MutableLiveData()
}
return mCurrentName as MutableLiveData<String>
}
open fun nameList(): MutableLiveData<List<String>> {
if (mNameListData == null) {
mNameListData = MutableLiveData()
}
return mNameListData as MutableLiveData<List<String>>
}
}
class FirstActivity : AppCompatActivity() {
companion object {
val TAG = FirstActivity.javaClass.simpleName
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myNameViewModel = ViewModelProviders.of(this).get(MyNameViewModel::class.java)
myNameViewModel.currentName().observe(this, Observer {
print(it)
})
myNameViewModel.nameList().observe(this, Observer {
if (it != null) {
for (item in it) {
print(item)
}
}
})
}
ViewModel
里面,定义两个方法,currentName
,和nameList
两个方法,并返回LiveData
对象。然后在activity
中通过ViewModelProviders.of(this).get(MyNameViewModel::class.java)
拿到viewModel
,最后通过observe
设置监听,observe
方法里面的两个参数LifecycleOwner owner
和Observer<T>
,最后在onChanged
方法中回调数据(这里kotlin
代码使用的是lamdba
表达式)。
用两个按钮模仿修改ViewModel
中保存的LiveData
数据:
btn_change_name.setOnClickListener {
myNameViewModel.currentName().setValue("Hubery")
}
btn_update_list.setOnClickListener {
var nameList = ArrayList<String>()
for (i in 0..9) {
nameList.add("Hubery<$i>")
}
myNameViewModel.nameList().setValue(nameList)
}
现在来看看LiveData
资源共享,也就是继承LiveData的例子:
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val mStockManager: StockManager
private val mListener = object : SimplePriceListener() {
fun onPriceChanged(price: BigDecimal) {
setValue(price)
}
}
init {
mStockManager = StockManager(symbol)
}
override fun onActive() {
mStockManager.requestPriceUpdates(mListener)
}
override fun onInactive() {
mStockManager.removeUpdates(mListener)
}
}
当LiveData
对象具有活动的观察者时调用OnActive
方法。LiveData
中的数据会调用setValue
方法去更新。
当LiveData
在没有任何的Observer
监听的时候,会调用Inactive
方法,在这里的例子会removeUpdate
方法。
LiveData的原理
借鉴ShymanZhu同学的关系图
LiveData
:是LiveData
组件里面非常核心的一个类,主要实现了observe
方法用于注册监听,setValue
用于主线程设置值,而postValue
子线程和主线程都可以。
MutabeLiveData
:继承了LiveData
,LiveData
是一个抽象类不能直接使用,在子类里面重写了postValue
和setValue
两个方法;
MediatorLiveData
:MediatorLiveData
继承了MutabeLiveData
;
LifecycleBoundObserver
:LifecycleBoundObserver
是LiveData
的内部类,
它继承了ObserverWrapper
并实现了GenericLifecycleObserver
,而这个GenericLifecycleObserver
又实现了LifecycleObserver
,有没有很熟悉?在Lifecycle
组件中通过LifecycleObserver
便可以观察到LifecycleOwner
中持有的Lifecycle
对象的生命周期变化。
Observer
:LiveData
有数据更新的时候就是通过Observer
接口的onChanged
方法告知界面(Activity,Fragment)
。
再次感谢ShymanZhu同学的时序图
上面大致的思路是:在
Fragment
中调用observe()
方法的时候,会先在方法内创建一个LifecycleBoundObserver
对象,然后通过getLifecycle().addObserver()
将这个创建好的对象添加进去。当生命周期会发生改变的时候,会调用相应的方法,移除观察者或者通知观察者更新数据;另外的调用LiveData
的setValue()
、postValue()
方法后,也会通知观察者更新数据。
我们首先根据上面的思路理一下,首选需要注册观察者,创建LifecycleBoundObserver
对象,生命周期发生变化之后通知观察者修改数据。
添加观察者
添加观察者有两个方法可以调用,observe
和observeForever
,先来看看这两个方法的实现:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
observe
方法中需要将LifecycleOwner
传入,而LifecycleOwner
的实现类可以通过getLifecycle()
,拿到Lifecycle
的生命周期;而observeForever
则不需要传入:
@MainThread
public void observeForever(@NonNull Observer<T> observer) {
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
通过observeForever()
添加的观察者,会永久收到数据变化的回调,除非用户手动removeObserve()
观察者会一直收到数据的变化的回调通知。
生命周期变化
先看看LifecycleBoundObserver
类的源码实现:
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
添加了观察者之后,生命周期发生改变的时候就会调用onStateChanged()
方法,当前的状态处于DESTROYED
的时候,观察者会被remove
,当当前的状态为active
的时候,调用activeStateChanged()
方法。
LiveData的数据更新
上面我们提到过,LiveData
的数据更新有两种方式,第一种就是使用setValue
的方式只能在主线程也就是UI线程里面调用,另外一种就是postValue
的方式可以在主线程或者子线程里面调用。
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
setValue
和postValue
在LiveData
中的实现:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
通过源码看到,postValue
最后也会调用setValue
方法,去修改LiveData
中的值。