-
概述
我们知道,页面中引用的数据放在ViewModel中,那么当ViewModel中的数据改变的时候怎样通知界面呢?我们可以通过持有Activity或者Fragment的实例来实现,但是在Android中组件实例的生命周期通常是易变的,随时可能销毁或者更改,所以按照原则,不能在生命周期长的类中引用生命周期短暂或者不可控的类的实例;并且,ViewModel中通常含有网络请求等异步操作,所以线程间异步通信也要考虑UI线程的问题,这些问题LiveData都做了很好的处理。
-
注册监听
通过调用LiveData的observe方法添加回调接口:
mViewModel.userId.observe(this, { ToastUtil.showDefaultToast(this, it) })
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); 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); }
回调接口owner是带有生命周期的组件实例,默认的ComponentActivity和Fragment都实现了这个接口,LifecycleBoundObserver持有了owner和observer,相当于把他们对应在一起,可见,回调接口实例被添加到了mObservers中。
-
关于数据变化的通知
在LiveData中,有两个通知改变数据的方法:setValue和postValue。但其实postValue最后也是调用了setValue:
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() { @SuppressWarnings("unchecked") @Override public void run() { Object newValue; synchronized (mDataLock) { newValue = mPendingData; mPendingData = NOT_SET; } setValue((T) newValue); } };
可以看到postValue只不过是通过Handler把回调接口放在队列中,以确保在主线程执行。
所以主要看一下setValue方法:
@MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); }
注意必须是主线程,保存数据。
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<? super T>, ObserverWrapper>> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext(); ) { considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while (mDispatchInvalidated); mDispatchingValue = false; }
注意此时dispatchingValue传入的是null,所以所有的mObservers中的监听回调都会被尝试执行:
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; observer.mObserver.onChanged((T) mData); }
上面为什么说尝试呢?因为我这里看到,在开头首先会判断observer的mActive是否为true,不为true则不会执行。注意observer.mLastVersion >= mVersion的判断,这是数据更新的关键:
public LiveData(T value) { mData = value; mVersion = START_VERSION + 1; } public LiveData() { mData = NOT_SET; mVersion = START_VERSION; } @MainThread protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null); }
可以看到只有在带有初始化值构造或者调用setValue方法更新值之后mVersion才会在原有基础上+1,所以每次dispatch的时候都要判断这个版本号,它决定着是否数据已更新,如果更新了才会通知回调方法执行,如果都通过了,最终执行到了我们监听回调接口的onChanged方法,显示Toast。
-
绑定监听的时候也会触发监听回调
除了setValue和postValue这种手动的通知监听的方式,当LiveData调用observe方法绑定到组件生命周期时也会触发监听回调,只不过在页面可见的时候(onStart之后)才会执行监听回调代码。
前面注册监听的时候我们看到,在observe方法中还有一句owner.getLifecycle().addObserver(wrapper)代码,用于把回调接口绑定到生命周期组件的监听回调集合里。
owner.getLifecycle()方法得到的是当前界面组件的LifecycleRegistry,看一下它的addObserver方法:
@Override public void addObserver(@NonNull LifecycleObserver observer) { State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED; ObserverWithState statefulObserver = new ObserverWithState(observer, initialState); ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver); if (previous != null) { return; } LifecycleOwner lifecycleOwner = mLifecycleOwner.get(); if (lifecycleOwner == null) { // it is null we should be destroyed. Fallback quickly return; } boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent; State targetState = calculateTargetState(observer); mAddingObserverCounter++; while ((statefulObserver.mState.compareTo(targetState) < 0 && mObserverMap.contains(observer))) { pushParentState(statefulObserver.mState); statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState)); popParentState(); // mState / subling may have been changed recalculate targetState = calculateTargetState(observer); } if (!isReentrance) { // we do sync only on the top level. sync(); } mAddingObserverCounter--; }
statefulObserver持有observer的状态在当前状态不是DESTROYED的时候是INITIALIZED,不存在的情况下存入mObserverMap中,这个是生命周期组件中持有的所有监听回调的集合,targetState是生命周期组件及其父组件中最新的状态,while是判断当前的observer的状态是否在生命周期最新状态之前,把执行状态在当前状态之前的所有Observer都尝试执行dispatchEvent,并且是已添加到mObserverMap的前提下,会执行statefulObserver.dispatchEvent方法:
void dispatchEvent(LifecycleOwner owner, Event event) { State newState = getStateAfter(event); mState = min(mState, newState); mLifecycleObserver.onStateChanged(owner, event); mState = newState; }
upEvent(statefulObserver.mState):
private static Event upEvent(State state) { switch (state) { case INITIALIZED: case DESTROYED: return ON_CREATE; case CREATED: return ON_START; case STARTED: return ON_RESUME; case RESUMED: throw new IllegalArgumentException(); } throw new IllegalArgumentException("Unexpected state value " + state); }
所以这里传入的event是ON_CREATE。
ObserverWithState持有的是前面传入的LifecycleBoundObserver和初始状态INITIALIZED:
ObserverWithState(LifecycleObserver observer, State initialState) { mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer); mState = initialState; }
对于LifecycleEventObserver类型的observer来说,Lifecycling.lifecycleEventObserver得到的就是observer本身,所以mLifecycleObserver.onStateChanged也就是LifecycleBoundObserver的onStateChanged方法:
@Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } activeStateChanged(shouldBeActive()); }
看一下activeStateChanged方法:
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); } }
如果mActive是true的话会执行dispatchingValue方法,mActive通过shouldBeActive()赋值:
@Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); }
可以看到,onStart之后才会触发事件回调。注意这里dispatchingValue传入的是this,即当前的ObserverWrapper,所以只会尝试执行当前Observer的回调。
我们可以从代码中看到,添加监听的时候会尝试dispatch回调,但是,我们前面的注册监听放在onCreate中,那么按照逻辑,在onStart之前的并不会被执行,但实际上为什么我们的监听在页面显示的时候自动执行了呢?其实自动执行是由Activity的生命周期方法触发的,使用ReportFragment来通知,ComponentActivity在onCreate的时候会调用ReportFragment.injectIfNeededIn(this):
public static void injectIfNeededIn(Activity activity) { if (Build.VERSION.SDK_INT >= 29) { // On API 29+, we can register for the correct Lifecycle callbacks directly activity.registerActivityLifecycleCallbacks( new LifecycleCallbacks()); } // Prior to API 29 and to maintain compatibility with older versions of // ProcessLifecycleOwner (which may not be updated when lifecycle-runtime is updated and // need to support activities that don't extend from FragmentActivity from support lib), // use a framework fragment to get the correct timing of Lifecycle events android.app.FragmentManager manager = activity.getFragmentManager(); if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) { manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit(); // Hopefully, we are the first to make a transaction. manager.executePendingTransactions(); } }
在sdk29以上会额外添加LifecycleCallbacks来回调,为了兼容以前的版本,下面的代码是添加一个没有任何界面的ReportFragment,只用它来处理生命周期通知的相关工作。
@Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); dispatchCreate(mProcessListener); dispatch(Lifecycle.Event.ON_CREATE); } @Override public void onStart() { super.onStart(); dispatchStart(mProcessListener); dispatch(Lifecycle.Event.ON_START); } @Override public void onResume() { super.onResume(); dispatchResume(mProcessListener); dispatch(Lifecycle.Event.ON_RESUME); } ... ... ... ...
可见是利用Fragment的生命周期来处理回调,看一下dispatch方法:
private void dispatch(@NonNull Lifecycle.Event event) { if (Build.VERSION.SDK_INT < 29) { // Only dispatch events from ReportFragment on API levels prior // to API 29. On API 29+, this is handled by the ActivityLifecycleCallbacks // added in ReportFragment.injectIfNeededIn dispatch(getActivity(), event); } }
可以看到,29以下的通过ReportFragment的dispatch方法发送生命周期回调通知:
static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) { if (activity instanceof LifecycleRegistryOwner) { ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event); return; } if (activity instanceof LifecycleOwner) { Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle(); if (lifecycle instanceof LifecycleRegistry) { ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event); } } }
我们看到调用了LifecycleRegistry的handleLifecycleEvent方法,这个方法中又调用了moveToState方法,moveToState又调用了sync方法,在sync中会调用forwardPass或backwardPass方法,这两个方法中都会调用和前面addObserver方法中类似的代码遍历mObserverMap,对符合执行时机的Observer调用dispatchEvent方法。
所以当界面显示的时候执行onStart回调时就会再次dispatchEvent,所以我们的监听回调此时就符合了“onStart之后执行”这个触发条件。
那么29以上的生命周期回调怎么处理呢?上面的注释也有提到,是根据ActivityLifecycleCallbacks来处理的。上面我们已经看到在ComponentActivity的onCreate的时候通过ReportFragment的injectIfNeededIn方法已经添加了一个LifecycleCallbacks:
static class LifecycleCallbacks implements Application.ActivityLifecycleCallbacks { @Override public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) { } @Override public void onActivityPostCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) { dispatch(activity, Lifecycle.Event.ON_CREATE); } ... ... }
然后在Activity的生命周期方法中都会调用相关的通知方法,以onStart来说:
protected void onStart() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this); mCalled = true; mFragments.doLoaderStart(); dispatchActivityStarted(); if (mAutoFillResetNeeded) { getAutofillManager().onVisibleForAutofill(); } }
其中调用了dispatchActivityStarted方法:
private void dispatchActivityStarted() { getApplication().dispatchActivityStarted(this); Object[] callbacks = collectActivityLifecycleCallbacks(); if (callbacks != null) { for (int i = 0; i < callbacks.length; i++) { ((Application.ActivityLifecycleCallbacks) callbacks[i]).onActivityStarted(this); } } }
可以看到,这里调用了每个ActivityLifecycleCallbacks的onActivityStarted方法,达到了生命周期通知回调的目的。
不管是ReportFragment中生命周期方法内调用还是LifecycleCallbacks调用,最后调用的都是同一个diapatch方法,都会走到LifecycleRegistry的handleLifecycleEvent中去。
-
和组件生命周期绑定
当调用LiveData的observe方法时:
@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe"); 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里面的mObservers会保存这个observer,这是为了数据改变的时候会调用这个observer来通知界面组件更新。
同时owner.getLifecycle().addObserver(wrapper)会在界面组件的LifecycleRegistry里的mObserverMap中也会保存一个observer:
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState); ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
而这里保存就是为了在组件销毁的时候自动解除绑定,避免内存泄露。
Activity通过LifecycleRegistry来通知生命周期变化的,在它的setCurrentState方法流程中,拿前进时的生命周期方法forwardPass方法来说(backwardPass也一样):
private void forwardPass(LifecycleOwner lifecycleOwner) { Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator = mObserverMap.iteratorWithAdditions(); while (ascendingIterator.hasNext() && !mNewEventOccurred) { Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next(); ObserverWithState observer = entry.getValue(); while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred && mObserverMap.contains(entry.getKey()))) { pushParentState(observer.mState); observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState)); popParentState(); } } }
这里会读取mObserverMap中所有的Observer来调用dispatchEvent方法,前面提到addObserver的时候mObserverMap保存的是ObserverWithState,所以会调用ObserverWithState的dispatchEvent方法:
void dispatchEvent(LifecycleOwner owner, Event event) { State newState = getStateAfter(event); mState = min(mState, newState); mLifecycleObserver.onStateChanged(owner, event); mState = newState; }
mLifecycleObserver就是前面构造ObserverWithState时传入的observer,也就是LifecycleBoundObserver,所以会调用它的onStateChanged方法:
@Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { if (mOwner.getLifecycle().getCurrentState() == DESTROYED) { removeObserver(mObserver); return; } activeStateChanged(shouldBeActive()); }
可以看到,如果当前界面组件已经销毁的话,这里会从LiveData的mObserver中移除当前的observer。
ViewModel之LiveData
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 原文链接:https://www.androidos.net.cn/doc/2020/9/26/478.html[...
- 原文链接:https://www.androidos.net.cn/doc/2020/9/26/478.html[...
- 前言 系列文章 Android Architecture Component之Lifecycle-Aware Co...
- 前言 系列文章 Android Architecture Component之Lifecycle-Aware Co...