一 什么是LiveData
LiveData是一个可观察数据变化的类,但是与其他观察类不同的是,LiveData是可以感知到所持有类的生命周期的。所以我们一般用它来和Activity、Fragment或者service一起使用。这里有个很有好处的地方就是,LiveData的onChange方法,只会在activity在前台的时候产生回调,后面我们可以用例子来说明。
二 LiveData的好处
那么使用LiveData有什么好处呢?从LiveData的相关特性,我们可以归纳出以下几点:
1 确保UI和数据状态保持一致
LiveData遵循观察者模式,当生命周期发生改变的时候,LiveData会通知观察者对象。因此我们可以通过统一在观察者对象数据中更新UI,而不是通过app数据的变更去改变UI。在我们这些对象发生变更的时候,我们的UI也会跟着改变。
2 不会有内存泄漏
所有的观察者都是绑定到owner的生命周期内的,也就是说,如果owner被finish的时候,所有的观察者也会被自动销毁。炒鸡智能方便有木有?
3 不会因为Activity被销毁而导致崩溃
这种情况多数发生在我们的异步回调函数中,比如有时候我们回去通过异步线程来获取网络数据后,刷新我们的界面。这个时候,当我们的activity被销毁的时候,我们的异步线程回调才刚回来,这就导致了我们在一个废弃的activity中更新他的UI,这就会导致异常崩溃的发生。
4 不再需要手动去控制生命周期
UI组件只会在对象不是stop或者resume的时候进行观察,LiveData会自动管理这一切。在正确的时候,给与观察者以回调。
5 永远保持最新的数据状态
当观察的对象不是处于激活状态的时候,LiveData并不会去刷新数据,而当观察的对象重新激活的时候,那么LiveData将会刷新最新的数据。最典型的是,如果你的Activity是后台的时候,再次期间所有的数据变更,liveData都会选择性的忽略,等到你重新唤醒Activity的时候,LiveData马上就会刷新他的值,让他和最后一个setValue(value)保持一致。
三 开始源码之旅
接下来,我们从一段简单的源码开始
viewModel.loadFiveUsers().observe(MainActivity.this, new Observer<List<User>>() { @Override public void onChanged(@Nullable List<User> users) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < users.size(); i++) { User user = users.get(i); sb.append("====================\n"); sb.append("uid:" + user.getUid() + "\n " + user.getUserName() + "\n" + user.getLastName() + "\n"); sb.append("\n"); } tv_values.setText(sb.toString()); } });
我们这里暂且忽略viewModel部门,我们只需要知道,viewModel.loadFiveUsers()返回的是一个LiveData<T>类型的数据就可以了。简单的说一下这段代码,就是实时获取当前数据库中的前5条数据,并且把这5条数据通过TextView显示出来。业务场景其实非常的简单。好了,接下来开始拆轮子
第一步:LiveData.observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)Owner和observe是如何建立联系的
我们进入源码的世界
@MainThreadpublic 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); }
首先,LiveData强调的是,observe方法必须是在UI线程中进行调用的。我们从源码可知
1 如果当前的owner是Destroyed状态的,那么我们就直接忽略掉了,这个是显而易见的。
2 LiveData会先将当前的owner和observe结合在一起,生成一个wrapper对象,然后尝试observe和wrapper当成key和value 添加进mObservers中,这个mObservers其实就是一个map对象。如果发现这个key对应的value已经有值了,并且这value并不是我们即将put进去的value,那么就会抛错
3 加入不存在的话,那么wrapper将会被添加进当前owner的生命周期中,进行监听。
第二步:setValue(T value)
LiveData提供了两个setValue的方法,一个是同步情况的调用
@MainThreadprotected 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); }
其实最后都是调用了 setValue((T) newValue);方法。我们来研究下这个方法,可以看到,他会先判断当前是否在主线程调用,如果不是的话,那么就会抛出错误。然后就会把当前LiveData的版本号mVersion++,把mData设置成最新的value。其实整个过程最麻烦的是dispatchingValue(null)这个方法。我们进入这个方法进行查看
private void dispatchingValue(@Nullable ObserverWrapper initiator) { if (mDispatchingValue) { mDispatchInvalidated = true; return; } mDispatchingValue = true; do { mDispatchInvalidated = false; if (initiator != null) { considerNotify(initiator); initiator = null; } else { for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; }
其实我们可以看到,这个个方法就是现在已有的观察者进行循环,检查到如果是当前的观察者,那么就调用considerNotify(iterator.next().getValue())方法。也即是找到最新的mData,进行onchanged(mData)回调给观察者。
private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { return; } // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet. // // we still first check observer.active to keep it as the entrance for events. So even if // the observer moved to an active state, if we've not received that event, we better not // notify for a more predictable notification order. if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; //noinspection unchecked observer.mObserver.onChanged((T) mData); }
其实这个方法,会调用到
@Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); }
这个方法就是会去判断当前的owner的状态是否是active状态,进行是否分发的动作。
四 生命周期中LiveData的回调情况
1 关于:永远保持最新的数据状态
我们主动setValue(T value)方法后,liveData调用的onChanged(T value)流程已经分析完毕了,那么前面我们所说的,当观察的对象不是处于激活状态的时候,LiveData并不会去刷新数据,而当观察的对象重新激活的时候,那么LiveData将会刷新最新的数据。最典型的是,如果你的Activity是后台的时候,再次期间所有的数据变更,liveData都会选择性的忽略,等到你重新唤醒Activity的时候,LiveData马上就会刷新他的值,让他和最后一个setValue(value)保持一致。这个是怎么实现的呢?
LifecycleBoundObserver 生命周期回调
其实就是如上图所说的,我们的activity在后台或者重新回到前台的时候,都会回调到上面的onStateChanged()方法。当Activity是后台的时候,shouldBeActive返回的是false,那么
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); } }
中的dispatchingValue(this)就不会进行分发,从而不会触发observe的onchanged(T mData) 方法。
2 Activity finish的时候,移除监听
上面的图中我们可以看到,LiveData还会去判断当前的owner是否已经被销毁了,如果被销毁了,还会调用removeObserver(mObserver);方法,这也就是我们不需要去关心内存泄漏,或者在Activity finish情况下,还去尝试更新UI的问题。
自此,LiveData的完整分析已经完成。
作者:gdutkyle
链接:https://www.jianshu.com/p/9e4ee7cb2bc0
共同學習,寫下你的評論
評論加載中...
作者其他優質文章