前言
4202年了,谁还用LiveData
,X都不用。
我也是这么想的,然后经历面试三联:
LiveData
用过吧?setValue()
和posValue()
有啥区别?原理是啥?observe()
和observeForever()
知道么? 原理是啥,数据是怎么分发的?LiveData
黏性知道怎么肥事吗?原理是啥?怎么解决?
我: 用过,post
不用管线程。observeForever()
一直等。黏性我看过 有个version
的原因。
面试官:你回去等消息吧。 然后面试评价 :基础不牢,深度不够。
基础用法
javascript
var testLiveData = MutableLiveData<String>()
//数据发送
testLiveData.setValue("")//主线程设置
testLiveData.postValue("")//可以在任何线程(包括后台线程)中调用
//数据接收
viewModel?.testLiveData?.observe(this){
//活动状态接收
}
viewModel?.testLiveData?.observeForever {
//不受 LifecycleOwner 生命周期的影响 要注意内存泄露
}
有深度(顺利装逼)回答
setValue()
和postValue()
的区别
typescript
@Override
public void setValue(T value) {
//调用父类方法
super.setValue(value);
}
@MainThread
protected void setValue(T value) {
//判断是否主线程
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
static void assertMainThread(String methodName) {
//异常抛出
if (!ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
+ " thread");
}
}
setValue()
在LiveData()
里 会判断当前线程是否是主线程,如果不是直接异常抛出。
那postValue()
为啥可以?
java
@Override
public void postValue(T value) {
super.postValue(value);
}
protected void postValue(T value) {
boolean postTask;
//加锁
synchronized (mDataLock) {
//如果当前mPendingData == 没设置
postTask = mPendingData == NOT_SET;
//mPendingData就等于新塞进来的数据
mPendingData = value;
}
if (!postTask) {
//如果当前 postTask 是false 也就说当前 不是NOT_SET状态 直接返回
return;
}
//发送数据 ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
// setValue
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
@Override
public void postToMainThread(@NonNull Runnable runnable) {
//主线程 post 数据
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
看完这些基础代码,大体明白,postValue()
就是丢了一个Runnable
给了主线程。所以他可以任意线程发送,但是主线程执行。我们看到postValue()
里面有个return
, 所以大家常说 数据过快,会丢数据的原因,其实就是!postTask return
导致。
observe()
和observeForever()
observe()
less
//初始化缓存
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =new SafeIterableMap<>();
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//检查是主线程么
assertMainThread("observe");
//检查当前是不是 DESTROYED
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
//构建 LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//判断是否需要执行的时候 已经缓存过了 再判断缓存的observer 是否已经添加到其他lifecycles 命中则直接扔异常
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);
}
// 如果已经存入返回缓存 否则返回null
public V putIfAbsent(@NonNull K key, @NonNull V v) {
Entry<K, V> entry = get(key);
if (entry != null) {
return entry.mValue;
}
put(key, v);
return null;
}
less
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) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
//如果销毁则自动移除
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
//追平生命周期状态 这里后面说 会涉生命周期绑定的问题
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
// 移除监听
mOwner.getLifecycle().removeObserver(this);
}
}
这里梳理下:
LiveData
里有一个mObservers
是一个Map
,在我们 调用 observe()
方法的时候,
第一步 :先判断当前线程,非主线程则抛出异常。
第二步:看当前 LifecycleOwner
的生命周期,是否属于活动状态 ,否则retrun
。
第三步:构建LifecycleBoundObserver
,构造函数里 将 传入的ower
复制给自己内部mOwner
。
调用putIfAbsent()
,以observer
为key
去查询 是否已经缓存,如果已缓存返回value
。无则缓存进去并,返回null
。
紧接着判断 如果当前observer
已经缓存了,并且和之前缓存进去的owner
不是一个,那就直接异常。告知一个observer
不能绑定不同的lifeclycle
。 确保observer
和owner
一一对应。
第四步:返回值 不为null
。直接返回,避免重复绑定。
第五步:ower
开始监听生命周期。
这里的第三步,正反查其实是很有意思的一个代码。
observeForever
java
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
//主线程检查
assertMainThread("observeForever");
//创建AlwaysActiveObserver
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);
}
observeForever()
相对看起来简单一些
第一步 :先判断当前线程,非主线程则抛出异常。
第二步:构建AlwaysActiveObserver
,构造函数里 将 传入的ower
复制给自己内部mOwner
。
调用putIfAbsent()
,以observer
为key
去查询 是否已经缓存,如果已缓存返回value。无则缓存进去并,返回null
。
紧接着判断 如果当前observer
已经缓存了,如果已经缓存的是一个LifecycleBoundObserver
,也就是监听生命周期的, 抛出异常。
第三步:返回值 不为null
。直接返回,避免重复绑定。
第四步:调用activeStateChanged()
,这里需要看一下 因为下面没代码了。
scss
void activeStateChanged(boolean newActive) {
// newActive 默认false
if (newActive == mActive) {
return;
}
mActive = newActive;
// 传入1
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
//分发数据 将自己也就是上文的AlwaysActiveObserver 传入进去
dispatchingValue(this);
}
}
ini
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
//因为我们传了this 不为null 所以走considerNotify
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;
}
kotlin
@SuppressWarnings("unchecked")
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
// AlwaysActiveObserver 的shouldBeActive 返回是true
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 判断版本 这个后面说
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//不管上面的代码,直接看这一句,回调数据
observer.mObserver.onChanged((T) mData);
}
这里简单的跑了一下流程 ,就知道 数据会被回调。至于怎么回调还不知道。
-
总结
observe
构建LifecycleBoundObserver
,会进行生命周期的相关拦截处理。observeForever
构建AlwaysActiveObserver
。- 两种都会保证相对的唯一性,在绑定之前都会检查是否是在主线程。
数据是怎么分发的?
关于数据的分发 ,我们还是要回到setValue()
和postValue()
setValue()
的数据分发
typescript
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
似乎分发数据的只有dispatchingValue()
,追进去看一下
ini
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
//因为我们传入是个null走这里 上面直接不看
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//发现 哎呦 怎么又走了considerNotify()方法。
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
因为我们传入是个null,
走else
, 我们发现这里代码意思就是 遍历 mObservers
取值,调用
considerNotify()
再次看一下这个方法。
kotlin
@SuppressWarnings("unchecked")
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);
}
ObserverWrapper
是从哪里来的? 需要我们思考一下。
其实很简单 调用 observe()
和observeForever()
的时候 往mObservers
存入进去。
ObserverWrapper
在observe
里 是 LifecycleBoundObserver
在 observeForever
是AlwaysActiveObserver
。
继续回看 considerNotify()
, 这里observer
是 LifecycleBoundObserver
调用 observer.mActive
,我们看下 mActive
是怎么来的。
less
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) {
//获取当前生命周期
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
//如果已经走入销毁状态,移除监听
removeObserver(mObserver);
return;
}
// 这里会递归追平生命周期
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
java
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() {
}
//被 LifecycleBoundObserver 的 onStateChanged 影响
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
dispatchingValue(this);
}
}
}
LifecycleBoundObserver
使用父类 ObserverWrapper
中的 mActive
,
而newActive
被activeStateChanged()
影响, 回看 LifecycleBoundObserver
的 onStateChanged
方法。LifecycleBoundObserver
实现 LifecycleEventObserver
监听生命周期,会回调onStateChanged()
,shouldBeActive()
表明起码在onStart()
后onPause()
之前。才返回true
。 这里while
会将当前状态再次配平。
再次回到 considerNotify()
,接下来的shouldBeActive()
我们知道其实就是看当前是否在活动状态,紧接着
ini
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
这个 mLastVersion
和mVersion
是什么?
ini
static final int START_VERSION = -1;
private abstract class ObserverWrapper {
final Observer<? super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;}
//mVersion 是liveData 属性
public LiveData(T value) {
mData = value;
mVersion = START_VERSION + 1;
}
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
START_VERSION
默认为-1
, observer
里的值 默认为 START_VERSION
,而LiveData
构建的时候 ,如果传了值则默认为 START_VERSION + 1
,否则为START_VERSION
。
追看一下代码,发现ObserverWrapper
中的mLastVersion
,除了初始值外,只有considerNotify()
方法中,会赋值。
mVersion
在liveData
调用setValue()
方法的时候 会++
;
typescript
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
至此 大体流程跑通,
LiveData
调用setValue()
, mVersion ++
,此刻从-1
到0
。
调用dispatchingValue(null)
;
mObservers
遍历所有缓存,判断如果当前页面还在活动,
如果ObserverWrapper
内置的 mLastVersion
比LiveData
的mVersion
(默认为-1)小 则回调执行,且赋值相等。
postValue()
的数据分发
ini
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
在前面我们讲过,其实原理mMainHandler.post(runnable)
; 将线程切换到了主线程。
我们关注下 mPostValueRunnable
做了什么。
less
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
//重新设置回NOT_SET
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
newValue
是为了在主线程中安全地传递并应用非主线程中提交的待更新值。
紧接着 调用 setValue()
调用 dispatchingValue()
这次要走上面
ini
@SuppressWarnings("WeakerAccess") /* synthetic access */
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;
}
继续 调用 considerNotify()
;
kotlin
private void considerNotify(ObserverWrapper observer) {
//AlwaysActiveObserver
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
这里的observer
其实是AlwaysActiveObserver
,第一步判断.mActive()
,我们之前看到
该值 受 activeStateChanged()
影响。
scala
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
static void assertMainThread(String methodName) {
if (!ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
+ " thread");
}
}
而我们在observeForever()
方法中 直接设置为了true
java
@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;
}
//设置为true
wrapper.activeStateChanged(true);
}
接下来 调用 shouldBeActive()
, AlwaysActiveObserver
返回true
,不进入
紧接着 对比了mLastVersion
和 mVersion
, 回调onChanged()
。
总结一下:
第一步:将mPostValueRunnable
切换子线程。
第二步: 赋值给newValue
,mPendingData
重置,调用setValue()
。
第三步: mVersion++
; 调用dispatchingValue()
第四步:走非空逻辑,调用considerNotify(initiator)
第五步:闯过2个判断,判断mLastVersion
和mVersion
,数据分发onChanged()
。
LiveData 的问题相关
数据倒灌问题
其实理论上来说,我认为这并不是一个问题,但是讲下什么情况会出现的原因
当新的观察者开始注册的时候,会将最后一次数据发送给当前。(当前页面是活动状态时候)
我们看下LifecycleBoundObserver
,while
这里 第一次肯定是不相等,则必定走
activeStateChanged()
less
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
而activeStateChanged
里走了 dispatchingValue()
继续走了 considerNotify()
,
ini
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
因为observer
是新的,则默认mLastVersion
为-1
,此刻liveData
内部有数据,肯定会回调一次。 然后配平mLastVersion
和mVersion
。
至于怎么解决,网上有很多方案。大家可自行百度 /谷歌。篇幅原因,不在赘述。
postValue()丢数据问题
在上面代码我们看到,postValue()
是将数据post
到主线程。等到执行才重置,才可以再次赋值。那在主线程未执行之前,就会丢数据。所以连续搞多次,可能就丢数据了。
ini
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);
}
};
错过数据更新
如果在Activity
或Fragment
的较晚生命周期阶段(如onResume()
之后)注册观察者,那么在这之前设置的LiveData
数据将不会被观察到,因为观察者错过了数据初次变更的通知。
这个可以参考源码里面的LifecycleBoundObserver.shouldBeActive()
方法。
最后
虽然在4202年的今天,LiveData
已经算比较落伍(捂脸我之前公司还在用),但是其中的源码解读,还是很有必要。
没有不好的框架,只有不好的代码。还是希望大家出去面试的时候,能够熟练的装X,维护住个人的巨佬形象,切莫学我,被人评价深度不够,回家吃灰。