LiveData是什么?
在官网以及网上有很多文章都会介绍LiveData
是什么、能够满足什么场景以及优势。假若用一句话概括,它就是与EventBus
有着类似功能的一个库--事件发布订阅机制。那么今天我们就来扒一扒它是如何实现的。本文将会以4个方面进行源码分析:
-
LiveData
是如何感知生命周期的? - 发布者发送数据后,订阅者是如何收到的?
- 粘性数据是如何产生的以及如何避免?
- 它与
EventBus
有什么区别?
简单使用
- 添加依赖
implementation "androidx.lifecycle:lifecycle-livedata:2.3.0"
- 简单demo
public class MainActivity extends AppCompatActivity {
private MutableLiveData mLiveData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 第一步
mLiveData = new MutableLiveData<>();
// 第二步
mLiveData.observe(this, new Observer() {
@Override
public void onChanged(String s) {
// 第四步
Log.e("MainActivity", s);
}
});
}
public void jump(View view) {
// 第三步
mLiveData.setValue("Hello");
}
}
LiveData
的使用非常简单,执行代码中的三个步聚,第四步就可以收到发送过来的信息。接下来分析每一步都做了一些什么事。
源码分析
- 构造
LiveData
对象
// MutableLiveData.java
public MutableLiveData() {
super();
}
// LiveData.java
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
LiveData
是一个抽象类,我们创建的MutableLiveData
是它的实现类。在父类的构造方法中,初始化了两个属性,一个是Object
类型的mData
字段,它的作用是用来保存我们通过setValue
传过来的值。另一个是int
类型的mVersion
字段,它的初始值为0。它有什么用呢?这里暂且先埋个坑。
-
observe
方法
// LiveData.java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
assertMainThread("observe");
// owner就是我们传过来的MainActivity,很显然State不可能为DESTROYED
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 注释1
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 注释2
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;
}
// 注释3
owner.getLifecycle().addObserver(wrapper);
}
先看注释1部分
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
将我们的生命周期拥有者,也就是我们的MainActivity
和我们在MainActivity
创建出来的观察者Observer
包装成了LifecycleBoundObserver,我们来看看其构造方法做了什么事。
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer super T> observer) {
super(observer);
mOwner = owner;
}
ObserverWrapper(Observer super T> observer) {
mObserver = observer;
}
自己保存着我们的MainActivity
的引用,调用父类ObserverWrapper
构造方法,保存我们创建的Observer
对象。在父类里面还有一个比较重要的int
类型的属性: mLastVersion
。上面有提到过mVersion
字段,现在又来一个mLastVerison
,猜测一下这两个字段是用来判断当前和上一次的版本,那具体是用来判断什么的呢?
再来看注释2部分
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
以我们创建的Observer
作为key,包装对象作为value添加到mObservers
集合中,被保存到Map
集合中的value还会被维护成双向链表。
public V putIfAbsent(@NonNull K key, @NonNull V v) {
Entry entry = get(key);
if (entry != null) {
return entry.mValue;
}
put(key, v);
return null;
}
protected Entry put(@NonNull K key, @NonNull V v) {
Entry newEntry = new Entry<>(key, v);
mSize++;
if (mEnd == null) {
mStart = newEntry;
mEnd = mStart;
return newEntry;
}
mEnd.mNext = newEntry;
newEntry.mPrevious = mEnd;
mEnd = newEntry;
return newEntry;
}
再来看注释3部分
// 这行代码就使得LiveData可以感知Activity的生命周期
owner.getLifecycle().addObserver(wrapper);
看到这里就明白了LiveData
是如何感知Activity的生命周期了。将LifecycleBoundObserver
作为生命周期的观察者,这样在生命周其变化时就会回调到onStateChanged
方法。addObserver
方法源码分析可以看手撕Jetpack组件之Lifecycle。
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();
}
}
...
}
setValue
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
记得在上文中有提到过mVersion
这个字段,初始值为0,此时变成了1,我们传的数据被mData
引用。继续跟进:
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, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
因在setValue
方法中传入的ObserverWrapper
为null
,所以会进入到else
条件里面去。上文有提到过生命周期持有者与我们创建的Observer
被包装成LifecycleBoundObserver
对象,然后又以Observer
为key,这个包装对象为value添加到mObservers
集合中。继续跟进considerNotify
方法。
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.
// 注释4
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 注释5
if (observer.mLastVersion >= mVersion) {
return;
}
// 注释6
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
先看注释6部分,observer.mObserver
指的就是我们在MainActivity
里面创建的Observer
,所以订阅者就收到了数据。
注释4和注释5是用来阻止数据回调的判断条件。先看注释4
// LifecycleBoundObserver
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
由LifecycleOwner
的状态决定返回值,因为这里的mOwner
就是我们的MainActivity
,此时我们是在setValue
的操作,状态已经变成RESUMED
,所以这里返回true。注释4的if语句内不会执行。
再看注释5部分,这两个属性在上文中多次提到,原来它们的作用是用来判断是否要回调观察察者的回调方法。mLastVersion
初始值为-1,mVersion
的值在setValue
时已经变成1了,所以注释5的条件也不成立。
到这里,整个源码分析就已经完毕。我们再来看看其它API的调用。
postValue
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
源码看起来比较简单。就是往主线程提交了一个Runnable
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
最终还是调到了setValue
。这两者的唯一区别就是setValue
只能在主线程,postValue
不受线程局限。
observeForever
该方法添加的Observer
并不受Activity的生命周期所约束。也就是说,当我们在Activity的onCreate
方法注册一个观察者时,若没有在onDestroy
方法中手动移除这个观察者,当Activity被销毁后,这个观察者仍然可以收到消息的回调。它是如何做到的?来看看其源码实现。
@MainThread
public void observeForever(@NonNull Observer super T> observer) {
assertMainThread("observeForever");
// 这里与observe方法一样,将我们传进来的observer包装成一个wrapper对象
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
// 将其放入到mObservers这个集合中
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);
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
// 看到我们上面分析过了的方法。不过这里的参数为上面的AlwaysActiveObserver
dispatchingValue(this);
}
}
由于dispatchingValue
方法的参数不为空,所以会进入这个方法的if
语句中,最终就会执行到上面提到的注释4部分。由于我们的观察者是被包装了AlwaysActiveObserver
对象,注释4部分的if
条件判断语句由这个类实现。
@Override
boolean shouldBeActive() {
return true;
}
这里它是直接返回了true,这也就使得它在没有被手动移除时,即使Activity销毁了仍然可以收到消息的原因。而我们前面提到LifecycleBoundObserver
,它实现这个方法是由当前Activity的生命周期的State来决定的。
粘性事件
在开发中共用同一个LiveData
是非常常见的,但随之也会产生一个副作用,数据粘性。也就是说,新注册一个观察者的时候,仍然可以收到上个观察者订阅的数据。比如我们在A界面跳转到B界面,在跳转之前,先用LiveData#setValue
一个值,此时在B界面的onCreate
方法用同一个LiveData
对象注册一个观察者,居然收到了上个界面发送来的数据。一般情况下,我们是不希望收到上个界面的数据的,那这产生的原因是什么呢?
在上文有多次提到过,LiveData
有两个比较重要的属性:Object
类型的mData
和int
类型的mVersion
,分别记录setValue
发过来的数据和类似某种计数机制数据发送的次数,每调用一次setValue
,这个次数都会++
。
界面AsetValue
之后,此时LiveData
中的mData
保存着数据,mVersion
为1。打开界面B,因为是在界面B的onCreate
方法内用LiveData
注册了一个新Observer
,根据上文提到LiveData
感知生命周期部分,会执行到LifecycleBoundObserver#onStateChanged
方法
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();
}
}
...
}
最终会执行到上文提到的注释5部分代码。因为在创建一个新LifecycleBoundObserver
时,它的mLastVersion
属性值-1,所以注释5部分的if
条件语句不成立,所以就会执行到注释6部分。这就是收到了上一个订阅者的数据原因。
如何避免这个问题了?
从理论上来分析,每个界面都使用自己的LiveData
,每次都创建一个新LiveData
对象。但由于在实际开发中,数据共享是非常常见的需求,所以这种方式并不是很完美。
通过上文的分析,在注释4和注释5这两个条件语句任意满足的话都可拦截订阅者收到发布者发布的数据。根据比较,注释5这个点是相对比较容易hook的。通过反射,在新注册Observer
时,把其包装对象LifecycleBoundObserver
中的mLastVersion
改成与当前LiveData
中的mVersion
一样的值就可以了。
思路分析:
- 想要修改
mLastVersion
字段,就需要先获取LifecycleBoundObserver
字节码对象 - 由于
LifecycleBoundObserver
是被保存在集合中,所以需要先获取mObservers
字节码对象 - 获取
mObservers
就需要先获取LiveData
的字节码对象
public class CustomLiveData extends MutableLiveData {
@Override
public void observe(@NonNull @NotNull LifecycleOwner owner, @NonNull @NotNull Observer super T> observer) {
super.observe(owner, observer);
try {
hook((Observer) observer);
} catch (Exception e) {
Log.e("CustomLiveData", "observe exception: " + e.getMessage());
}
}
private void hook(Observer observer) throws Exception {
Class liveDataClass = LiveData.class;
Field mObserversField = liveDataClass.getDeclaredField("mObservers");
mObserversField.setAccessible(true);
Object mObservers = mObserversField.get(this);
// 因为在Map中获取value时是通过get方法获取,所以还需要拿到这个get方法的字节码对象
Method getMethod = mObservers.getClass().getDeclaredMethod("get", Object.class);
getMethod.setAccessible(true);
// 我们传进来的Observer被作为key,与LifecycleBoundObserver存入到mObservers中
Object entry = getMethod.invoke(mObservers, observer);
// LifecycleBoundObserver
Object lbo = null;
if (entry instanceof Map.Entry) {
lbo = ((Map.Entry) entry).getValue();
}
if (lbo == null) {
throw new NullPointerException("observerWrapper为空");
}
// mLastVersion是在父类中,先获取父类ObserverWrapper字节码对象
Class> observerWrapperClass = lbo.getClass().getSuperclass();
Field mLastVersionField = observerWrapperClass.getDeclaredField("mLastVersion");
mLastVersionField.setAccessible(true);
Field mVersionField = liveDataClass.getDeclaredField("mVersion");
mVersionField.setAccessible(true);
Object mVersionValue = mVersionField.get(this);
mLastVersionField.set(lbo, mVersionValue);
}
}
该解决方案参考Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus
之前有用过美团的这个LiveDataBus这个库,但发现一个问题就是短时间内发送多个事件给同一个Observer
会出现只收到一个。
上面的方案使用的是反射,我们还可以使用一个包装类来实现。
public class ObserverWrapper implements Observer {
private final StickyLiveData mLiveData;
private final Observer mObserver;
private final boolean isSticky;
private int mLastVersion;
public ObserverWrapper(StickyLiveData stickyLiveData, Observer observer, boolean isSticky) {
mLiveData = stickyLiveData;
mObserver = observer;
this.isSticky = isSticky;
mLastVersion = mLiveData.getVersion();
}
@Override
public void onChanged(T t) {
if (mLastVersion >= mLiveData.getVersion()) {
// //但如果当前observer它是关心 黏性事件的,则给他。
if (isSticky && mLiveData.getStickyData() != null) {
mObserver.onChanged(mLiveData.getStickyData());
}
return;
}
mLastVersion = mLiveData.getVersion();
mObserver.onChanged(t);
}
}
public class StickyLiveData extends LiveData {
private T mStickyData;
private int mVersion = 0;
private final OnDestroyCallback mCallback;
public interface OnDestroyCallback {
void onDestroy();
}
public StickyLiveData(@NonNull OnDestroyCallback callback) {
this.mCallback = callback;
}
@Override
protected void setValue(T value) {
mVersion++;
super.setValue(value);
}
@Override
protected void postValue(T value) {
mVersion++;
super.postValue(value);
}
public void setStickyData(T stickyData) {
this.mStickyData = stickyData;
setValue(stickyData);
}
public void postStickyData(T stickyData) {
this.mStickyData = stickyData;
postValue(stickyData);
}
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
observeSticky(owner, observer, false);
}
public void observeSticky(LifecycleOwner owner, Observer super T> observer, boolean isSticky) {
super.observe(owner, new ObserverWrapper(this, observer, isSticky));
owner.getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
mCallback.onDestroy();
}
}
});
}
public T getStickyData() {
return mStickyData;
}
public int getVersion() {
return mVersion;
}
}
public class LiveDataBus {
private final ConcurrentHashMap mHashMap = new ConcurrentHashMap<>();
private static final SingletonHelper INSTANCE =
new SingletonHelper() {
@Override
protected LiveDataBus create() {
return new LiveDataBus();
}
};
public static LiveDataBus get() {
return INSTANCE.get();
}
public StickyLiveData with(String eventName) {
StickyLiveData liveData = mHashMap.get(eventName);
if (liveData == null) {
liveData = new StickyLiveData<>(new StickyLiveData.OnDestroyCallback() {
@Override
public void onDestroy() {
mHashMap.remove(eventName);
}
});
mHashMap.put(eventName, liveData);
}
return liveData;
}
}
public abstract class SingletonHelper {
public SingletonHelper() {
}
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
这个库 UnPeek-LiveData也是处理LiveData
粘性事件的,有兴趣的也可以去查看。
与EventBus的区别
-
LiveData
可以自动感知Activity/Fragment的生命周期,EventBus
做不到。 -
EventBus
需要手动取消事件的注册,LiveData
不需要。 -
LiveData
是通过接口回调的方式通知订阅者,EventBus
通过反射找到标有其注解的方法通知订阅者。