简述:
liveData持有一个版本,observer持有一个版本,当livedata.setValue时,如果observer的版本低于livedata版本并且observer是活跃状态时,observer的onchange才会被调用
另外lifeCycleOwner在切换到活跃态时会给observer发送最新数据,以及在切换到DESTROYED时会移除observer
还有就是粘性数据
https://zhuanlan.zhihu.com/p/593472898
Featrue
UI和实时数据保持一致 因为LiveData采用的是观察者模式,这样一来就可以在数据发生改变时获得通知,更新UI。
避免内存泄漏 观察者被绑定到组件的生命周期上,当被绑定的组件销毁(destroy)时,观察者会立刻自动清理自身的数据。
不会再产生由于Activity处于stop状态而引起的崩溃 ,例如:当Activity处于后台状态时,是不会收到LiveData的任何事件的。
不需要再解决生命周期带来的问题 LiveData可以感知被绑定的组件的生命周期,只有在活跃状态才会通知数据变化。
实时数据刷新 当组件处于活跃状态或者从不活跃状态到活跃状态时总是能收到最新的数据。
解决Configuration Change问题 在屏幕发生旋转或者被回收再次启动,立刻就能收到最新的数据。
数据实时更新、安全更新:当liveData的setValue被调用时,会遍历自身所有observer并considerNotify,此时会判断observer的活跃状态(shouldBeActive)和内部版本,决定是否向其发送通知。
避免内存泄漏:传入lifeCycleOwner即走observe()的LiveData会在lifeCycleOwner回调onStateChanged为DESTROYED的时候移除掉observer防止内存泄露,而相对的observeForever则由于没有owner而无此特性。
解决Configuration Change问题、粘性数据:一般而言observer是在onCreate中调用的,liveData.observer方法在调用时也会立即被推送liveData中最后一次数据。(会导致所谓的数据倒灌)。Configuration Change时会ViewModel会从当前Activity或fragmentManager的viewModelStore的缓存中重新取出,而ViewModel中的liveData自然也会保留。
常用实现类 https://chatgpt.com/c/21580ee8-b685-48be-a510-712388ae346e
LiveData常用于MVVM中,ViewModel向View层提供订阅的单向数据源。一般实践中会根据”单一数据源真相”原则,在ViewModel层中收敛所有的可变MutableLiveData,只对View层提供不可变的LiveData。View层行为应通过调用ViewModel的方法变更数据。
在MVVM架构中,View层不应该直接改变ViewModel中的数据状态。这是为了保持清晰的职责分离和确保数据的一致性。具体来说:
View层 :主要负责显示数据和处理用户交互。它可以观察LiveData
并根据数据变化更新UI。
ViewModel层 :负责准备和管理与UI相关的数据。它通过MutableLiveData
更新数据,并暴露LiveData
给View层以供观察。
Model层 :负责数据操作,如网络请求和数据库操作。
工作流程
View观察ViewModel中的LiveData :View层通过观察ViewModel中暴露的LiveData
,接收数据变化并更新UI。
用户交互通过View通知ViewModel :当用户与UI交互时,View层调用ViewModel中的方法,传递用户动作或输入。
ViewModel更新数据 :ViewModel处理用户的输入,进行必要的业务逻辑处理,并通过更新MutableLiveData
来改变数据状态。
View层收到更新并更新UI :由于View观察了LiveData
,当ViewModel中的数据状态发生变化时,View会自动收到通知并更新UI。
假设你有一个按钮点击事件来更新数据:
1 2 3 4 5 6 7 8 viewModel.buttonClicked.observe(this , Observer { newText -> textView.text = newText }) button.setOnClickListener { viewModel.onButtonClicked() }
在ViewModel中:
1 2 3 4 5 6 7 8 9 class TestViewModel : ViewModel () { private val _buttonClicked: MutableLiveData<String> = MutableLiveData() val buttonClicked: LiveData<String> = _buttonClicked fun onButtonClicked () { _buttonClicked.value = "按钮点击了" } }
关键点
View层不直接修改数据 :View层通过调用ViewModel中的方法来请求数据更新,而不是直接修改LiveData
。
ViewModel负责数据更新 :ViewModel接收View层的请求,更新MutableLiveData
中的数据。
数据变化通知View层 :LiveData
的数据变化会通知观察者(View层),并更新UI。
通过这种方式,确保了View层与ViewModel层之间的职责清晰分离,并且数据状态的管理是集中且可控的。
LiveData
不可变的(一般作为ViewModel对View层提供的单向数据源)
MutableLiveData 可变的(一般用于ViewModel层内部变更数据,会用对外提供LiveData同名加下划线前缀命名)
https://developer.android.com/reference/android/arch/lifecycle/MutableLiveData
可变的、监听多源的
https://developer.android.com/reference/android/arch/lifecycle/MediatorLiveData
原理 我们知道 livedata 的使用很简单,它是采用观察者模式实现的
添加观察者
在数据改变的时候设置 value,这样会回调 Observer 的 onChanged 方法
1 2 3 4 5 6 7 public interface Observer<T> { /** * Called when the data is changed. * @param t The new data */ void onChanged(T t); }
observe方法 LiveData包含两个用于添加数据观察者(Observer)的方法,分别是
observe(LifecycleOwner , Observer) 生命周期安全的
observeForever(Observer)
两个方法的区别对于外部来说只在于是否提供了生命周期安全的保障。
生命周期安全的observe 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @MainThread public void observe (@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { assertMainThread("observe" ); if (owner.getLifecycle().getCurrentState() == DESTROYED) { 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); }
传入的LifecycleOwner
参数意味着携带了Lifecycle对象,LiveData内部就根据 Lifecycle的生命周期事件的回调变化在合适的时机进行数据通知,并在 Lifecycle对象处于DESTROYED状态时自动移除Observer,这也是LiveData避免内存泄漏的最重要的一个点。
上面的代码使用到了LifecycleBoundObserver
,它是抽象类ObserverWrapper的实现类。ObserverWrapper用于包装外部传进来的Observer对象,为子类定义好特定的抽象方法和共用逻辑,主要是提供了共用的状态分发函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super (observer); mOwner = owner; } @Override boolean shouldBeActive () { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } @Override public void onStateChanged (@NonNull LifecycleOwner source, @NonNull 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 ); } }
LifecycleBoundObserver会保证当LiveData依赖的生命周期转到非活跃时,不进行通知(如果DESTROY会直接移除Observer);当转到活跃时且数据版本更新了则向其发起回调。
LifecycleBoundObserver的整个事件流程是这样的:
Lifecycle的生命周期发生变化,从而回调了onStateChanged函数
onStateChanged函数首先判断Lifecycle是否已处于DESTROYED状态,是的话则直接移除Observer,整个回调流程结束,否则则继续以下流程
onStateChanged调用了activeStateChanged()函数,activeStateChanged()函数判断Lifecycle的活跃状态是否发生了变化,如果从非活跃状态切换到了活跃状态,是的话则调用dispatchingValue()函数来分发值,最终再根据ObserverWrapper内部的value版本号mLastVersion来判断是否有新值需要向其回调,是的话则向其回调新值,否则则返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 private abstract class ObserverWrapper { final Observer<? super T> mObserver; boolean mActive; int mLastVersion = START_VERSION; ObserverWrapper(Observer<? super T> observer) { mObserver = observer; } abstract boolean shouldBeActive () ; boolean isAttachedTo (LifecycleOwner owner) { return false ; } void detachObserver () { } void activeStateChanged (boolean newActive) { if (newActive == mActive) { return ; } 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 ); } } }
ObserverWrapper一共有两个子类:
LifecycleBoundObserver和AlwaysActiveObserver,两者的差别就在于是否和生命周期相绑定 。
非生命周期安全的observeForever 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @MainThread public void observeForever (@NonNull Observer<? super T> observer) { assertMainThread("observeForever" ); AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer); ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper); if (existing instanceof LiveData.LifecycleBoundObserver) { throw new IllegalArgumentException("Cannot add the same observer" + " with different lifecycles" ); } if (existing != null ) { return ; } wrapper.activeStateChanged(true ); }
上面代码使用到了AlwaysActiveObserver,它也是抽象类ObserverWrapper的实现类,其shouldBeActive()返回值固定为true,意味着只要有数据变化都会进行回调。所以使用observeForever()函数一定要在过后主动移除Observer
,避免内存泄露和NPE。
更新LiveData的值 更新LiveData的值的方法一共有两个,分别是:
setValue(T value)
postValue(T value)
setValue setValue(T)函数被限定在只能主线程进行调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /** * Sets the value. If there are active observers, the value will be dispatched to them. * <p> * This method must be called from the main thread. If you need set a value from a background * thread, you can use {@link #postValue(Object)} * * @param value The new value */ @MainThread protected void setValue(T value) { assertMainThread("setValue"); //更新当前 value 的版本号,即 value 的新旧程度 mVersion++; mData = value; dispatchingValue(null); }
dispatchingValue()
函数设计得比较巧妙,用两个全局的布尔变量mDispatchingValue和mDispatchInvalidated就实现了新旧值判断、旧值舍弃、新值重新全局发布的逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private void considerNotify (ObserverWrapper observer) { if (!observer.mActive) { return ; } if (!observer.shouldBeActive()) { observer.activeStateChanged(false ); return ; } if (observer.mLastVersion >= mVersion) { return ; } observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData); }
postValue 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 protected void postValue (T value) { boolean postTask; synchronized (mDataLock) { postTask = mPendingData == NOT_SET; mPendingData = value; } if (!postTask) { return ; } ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); }
postValue(T)函数不限定调用者所在线程,不管是主线程还是子线程都可以调用,因此是存在多线程竞争的可能性的,postValue(T)函数的重点旧在于需要理解其从子线程切换到主线程之间的状态变化。
在mPostValueRunnable被执行前,所有通过postValue(T)函数传递的value都会被保存到变量mPendingData上,且只会保留最后一个
,直到mPostValueRunnable被执行后mPendingData才会被重置,所以使用 postValue(T) 函数在多线程同时调用或者单线程连续调用的情况下是存在丢值(外部的 Observer 只能接收到最新值)的可能性的。
Issue 连续postValue()吞数据 Google在postValue的注释上说明了
If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched. 如果在主线程执行一个已发布的任务之前多次调用此方法,则只会分派最后一个值。
只有第一次调用时会走到postToMainThread(mPostValueRunnable),后面所有执行的postValue在执行完postTask = mPendingData == NOT_SET 和 mPendingData = value 后,直接由于之后postTask == false,所以return掉了,也就不会再postToMainThread一次而是只修改mPendingData数据。
直到主线程中mPostValueRunable执行方法中会将真正调用setValue并将mPendingData重置为NOT_SET.
这个实现其实听起来很像View的刷新,比如TextView连续设置两次文本,也是只有当Vsync到来时取最新的文本设置到TextView中
粘性事件(数据倒灌) LiveData 本身被设计为粘性事件,也即,一旦 LiveData 持有数据 ,那么在观察者订阅该 LiveData 时,会被立即推送最后一次数据。(当observe时会立即回调onChange推送数据)
现有解决方案及各自缺陷
美团方案:反射hook LiveData的observe 方法,在observe方法中先将livedata的version赋值给observer(存在于ObserverWrapper中)
官方方案:SingleLiveEvent,实现SingleLiveEvent继承MutableLiveData,用一个boolean变量pending标记 ,每次setValue只会导致最多一次onChange
SourceCode 解决数据倒灌-美团方案: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 private static class BusMutableLiveData <T > extends MutableLiveData <T > { private Map<Observer, Observer> observerMap = new HashMap<>(); @Override public void observe (@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) { super .observe(owner, observer); try { hook(observer); } catch (Exception e) { e.printStackTrace(); } } @Override public void observeForever (@NonNull Observer<T> observer) { if (!observerMap.containsKey(observer)) { observerMap.put(observer, new ObserverWrapper(observer)); } super .observeForever(observerMap.get(observer)); } @Override public void removeObserver (@NonNull Observer<T> observer) { Observer realObserver = null ; if (observerMap.containsKey(observer)) { realObserver = observerMap.remove(observer); } else { realObserver = observer; } super .removeObserver(realObserver); } private void hook (@NonNull Observer<T> observer) throws Exception { Class<LiveData> classLiveData = LiveData.class; Field fieldObservers = classLiveData.getDeclaredField("mObservers" ); fieldObservers.setAccessible(true ); Object objectObservers = fieldObservers.get(this ); Class<?> classObservers = objectObservers.getClass(); Method methodGet = classObservers.getDeclaredMethod("get" , Object.class); methodGet.setAccessible(true ); Object objectWrapperEntry = methodGet.invoke(objectObservers, observer); Object objectWrapper = null ; if (objectWrapperEntry instanceof Map.Entry) { objectWrapper = ((Map.Entry) objectWrapperEntry).getValue(); } if (objectWrapper == null ) { throw new NullPointerException("Wrapper can not be bull!" ); } Class<?> classObserverWrapper = objectWrapper.getClass().getSuperclass(); Field fieldLastVersion = classObserverWrapper.getDeclaredField("mLastVersion" ); fieldLastVersion.setAccessible(true ); Field fieldVersion = classLiveData.getDeclaredField("mVersion" ); fieldVersion.setAccessible(true ); Object objectVersion = fieldVersion.get(this ); fieldLastVersion.set(objectWrapper, objectVersion); } }
解决数据倒灌-官方方案 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class SingleLiveEvent <T > : MutableLiveData <T > () { private val mPending = AtomicBoolean(false ) @MainThread override fun observe (owner: LifecycleOwner , observer: Observer <in T >) { if (hasActiveObservers()) { Log.w(TAG, "Multiple observers registered but only one will be notified of changes." ) } super .observe(owner) { t -> if (mPending.compareAndSet(true , false )) { observer.onChanged(t) } } } @MainThread override fun setValue (t: T ?) { mPending.set (true ) super .setValue(t) } }