Android架构组件之LiveData
如果你看过了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_one.png
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同学的时序图
LiveData_two.png
上面大致的思路是:在
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中的值。