LiveData是一个数据持有类,它可以通过添加观察者被其他组件观察其变更。不同于普通的观察者,它最重要的特性就是遵从应用程序的生命周期,如在Activity中如果数据更新了但Activity已经是destroy状态,LivaeData就不会通知Activity(observer)。当然LiveData的优点还有很多,如不会造成内存泄漏等。LiveData通常会配合ViewModel来使用,ViewModel负责触发数据的更新,更新会通知到LiveData,然后LiveData再通知活跃状态的观察者。
直接从observe方法入手
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// 判断是否在主线程,不是则报错
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore 如果Activity/fragment已经销毁了,那么忽略
return;
}
// 重点代码,包装了一个LifecycleBoundObserver,将外部出入的owner和observer封装了一层
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 重点代码,mObservers=SafeIterableMap, ObserverWrapper>,可以把它看作Map
// 这里的目的就是尝试保存到map,返回值可以用来判断是第一次添加还是说之前已经添加过
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
// 如果返回值存在,那么说明不是第一次put到Map缓存中,那么避免重复添加,这里直接抛出异常了
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
// 已经添加过观察者,直接返回
return;
}
// 如果owner没有添加过观察者,那么才添加,注意这里添加的并不是我们外面传入的,而已经过包装过后的LifecycleBoundObserver
// 当添加了Lifecycle的观察者后,LifecycleBoundObserver就能感知owner的生命周期了
owner.getLifecycle().addObserver(wrapper);
}
下面就来看看LifecycleBoundObserver到底是何方神圣
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull
final LifecycleOwner mOwner; // 真正的外部传入的LifecycleOwner
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer); // 这里将外部传入的观察者传给了父类ObserverWrapper
mOwner = owner;
}
@Override
boolean shouldBeActive() {
// 这里状态要start之后才表示激活了
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// 实现GenericLifecycleObserver的接口方法,由LifeCycler回调
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
// 当目标不可见的时候调用liveData的removeObserver方法,将外部传入的观察者移除掉
removeObserver(mObserver);
return;
}
// 重点代码:通知父类ObserverWrapper状态变化,后面会介绍
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
// 是否添加到目标owner中
return mOwner == owner;
}
@Override
void detachObserver() {
// 目标lifeCycle异常观察者,注意传入的是this,也就是包装后的
mOwner.getLifecycle().removeObserver(this);
}
}
上面代码并不多,LifecycleBoundObserver 继承自LiveData的内部类ObserverWrapper 并实现了 GenericLifecycleObserver接口,而 GenericLifecycleObserver 接口又继承自 LifecycleObserver 接口,那么根据 Lifecycle 的特性,实现了LifecycleObserver接口并且加入 LifecycleOwner 的观察者里就可以感知或主动获取 LifecycleOwner 的状态。
我们来看看ObserverWrapper源码
// 这是定义在LiveData内部的抽象类
private abstract class ObserverWrapper {
// 这里的观察者其实就是我们外面传入的,也就是它的子类LifecycleBoundObserver的构造方法赋值的
final Observer<? super T> mObserver;
boolean mActive; // 标记是否激活了
// 重点代码,标记最后一次发送数据的版本,默认是-1
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer; // 子类继承后需要调用usper来赋值
}
// 抽象方法,由子类LifecycleBoundObserver实现
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;// 默认是false,子类会重写此方法
}
void detachObserver() {
}
// 重点方法:也是由子类调用,用来更新状态,当子类的生命周期状态监听发生变化就会回调到这里
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) {
// 回调给LiveData,当前是激活状态
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
// 回调给LiveData,当前是非激活状态
onInactive();
}
if (mActive) {
// 如果激活了,调用下面方法进行分发,后面会重点介绍,这个方法是LiveData的方法
dispatchingValue(this);
}
}
}
来看看LifecycleEventObserver接口,很简单,只是继承了LifecycleObserver,并且提供了一个方法用来通知状态变更
public interface LifecycleEventObserver extends LifecycleObserver {
/**
* Called when a state transition event happens.
*
* @param source The source of the event
* @param event The event
*/
void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);
}
分析到这里,我们可以清楚的知道,当我们调用LiveData的observer的时候其实是调用了owner的getLifecycle().addObserver添加了一个经过包装后的LifecycleBoundObserver观察者
看完了上面观察者的注册分析后,那么我们的LiveData什么时候会通知观察者呢?不用想,肯定是数据更新的时候,而数据的更新是我们代码自己控制的,如请求网络返回User信息后,我们会主动将User放入MutableLiveData中,这个时候就要用到postValue或者setValue方法了,由于LiveData是一个抽象类且这2个方法都是protected的,而它的子类MutableLiveData中是重写了这2个方法的.
public class MutableLiveData<T> extends LiveData<T> {
// 带参数构造方法
public MutableLiveData(T value) {
super(value);
}
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value); // 调用super方法
}
@Override
public void setValue(T value) {
super.setValue(value); // 调用super方法
}
}
来看看父类做了啥
static final int START_VERSION = -1;
private volatile Object mData; // 维护的数据
private int mVersion = START_VERSION; // 维护的版本,每次发送数据都会自增
// 运行在子线程
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方法发送数据
setValue((T) newValue);
}
};
// 运行在主线程
@MainThread
protected void setValue(T value) {
assertMainThread("setValue"); // 判断是否在主线程
mVersion++; // 重点代码,版本自增
mData = value; // 保存数据
// 重点方法
dispatchingValue(null);
}
可以看到调用 dispatchingValue()方法并传入null,表示将数据分发给各个观察者, 下面来分析此方法的具体逻辑
private boolean mDispatchingValue; // 标记当前是否正在分发数据
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
// 更新标记
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
// 标注1:如果传入的不是null,那么调用下面的方法通知观察者
// 还记得上面分析ObserverWrapper源码的activeStateChanged方法吗
// 没错当LifecycleBoundObserver监听到owner状态变化后会调用其父类ObserverWrapper的activeStateChanged方法,
// 然后activeStateChanged方法会在mActive=true的时候调用considerNotify方法
considerNotify(initiator);
initiator = null;
} else {
// initiator=null进来
// 否则遍历所有的观察者,还记得这里的map吗,他就是mObservers,key=observer,value=LifecycleBoundObserver
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
//标注2: 通知所有的LifecycleBoundObserver
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
从标注1可以看出,dispatchingValue()参数传null和不传null的区别就是如果传null将会通知所有的观察者,反之仅仅通知传入的观察者。我们直接看标注2,通知所有的观察者通过遍历 mObservers ,将所有的 ObserverWrapper 拿到,实际上就是我们上面提到的 LifecycleBoundObserver,通知观察者调用considerNotify()方法,这个方法就是通知的具体实现了。
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
// 如果LifecycleBoundObserver维护的状态,切切来说是它的父类ObserverWrapper的mActive=false,那么忽略数据的发送
return;
}
// 这里通过observer.shouldBeActive间接的判断owner的状态,这里主动调用一次也是为了保证状态更加精确
// 因为上面的observer.mActive判断是被动监听的
if (!observer.shouldBeActive()) {
// 如果owner的状态不可见,那么通知状态变化,更新的observer.mActive的值=false
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
// 重点方法,对比LifecycleBoundObserver的mLastVersion版本和LiveData的版本mVersion,如果相同或者大于LiveData的,则忽略数据的发送
return;
}
// 上面经过重重筛选后来到这里,说明是需要发送数据,更新mLastVersio的版本
// 而mVersion的值在上面分析postValue方法的时候我们知道每次调用的时候都会自增
observer.mLastVersion = mVersion;
// 通知真正的观察者,也就是我门注入的观察者,它维护在LifecycleBoundObserver中
observer.mObserver.onChanged((T) mData);
}
如果观察者不是活跃状态,将不会通知此观察者,看最后一行,observer.mObserver.onChanged((T) mData),observer.mObserver就是我们调用LiveData的observer()方法传入的 Observer,然后调用 Observer 的 onChanged((T) mData)方法,将保存的数据mData传入,也就实现了更新。在看下我们实现的Observer:
viewModel.getUser().observe(MainActivity.this, new Observer<User>() {
@Override
public void onChanged(@Nullable User user) {
if (user != null) {
tvUser.setText(user.toString());
}
}
});
如果哪个控件要根据user的变更而及时更新,就在onChanged()方法里处理就可以了。到这里,LiveData已经能够分析完了,其实LiveData的实现还是要依赖于Lifecycle。
即发射的事件如果早于注册,那么注册之后依然可以接收到的事件称为粘性事件。
粘性事件通常会出现在多个页面共用同一个单例的LiveData对象的场景,究其原因就是因为LiveData的mVersion大于LifecycleBoundObserver的mLastVersion导致的。因为LiveData的mVersion是用来标记发送数据的次数的,每调用一次postValue或者setValue方法就会让mVersion自增一次,而前面分析源码的时候我门知道当mVersion > mLastVersion的时候就会将数据发送给我们设置的观察者的onChanged方法。
至于为什么初次设置监听会出现mVersion > mLastVersion的情况呢?
首先我需要说明下,mVersion和mLastVersion的默认值都是等于START_VERSION常量,它的值就是-1, 因此我们第一次使用LiveData肯定是mVersion=mLastVersion=-1的,因此首次设置observer进行监听的时候是不会出现粘性事件。
但是,如果现在有2个Activity页面分别是A页面和B页面,A和B页面都是同时使用一个单例的LiveData对象,下面开始分析:
A页面设置监听,同时发送一次数据,那么LiveData的mVersion+1后变成0, 同时A页面设置observer会收到通知,因为LifecycleBoundObserver第一次添加到Lifecycler的时候,它的mLastVersion=-1,因此满足mVersion>mLastVersion, 所有A页面能收到通知,而此时B页面还没有打开,所以并没有触发添加监听的操作,因此B收不到通知。
A页面跳到B页面,B页面在onCreate使用同一个LiveData进行事件的observer监听,它会立刻收到粘性事件,因为此时的LiveData的mVersion变成了0, 而B页面Lifecycler在注册observer的时候也是一个新的LifecycleBoundObserver, 即mLastVersion是-1,因此满足mVersion>mLastVersion,所以B页面收到粘性事件。
由于粘性事件是在设置observer的时候发生,因此我们还是从LiveData的observer方法入手分析
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);
}
此处getLifeCycle获取的对象是LifecycleRegistry对象,查看AppcompatActivity的getLifecycle方法就可以知道原因了,它最终会调用ComponentActivity的getLifecycle方法
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
...
// 这里可知mLifecycleRegistry就是LifecycleRegistry对象
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
public Lifecycle getLifecycle() {
// 返回一个mLifecycleRegistry对象
return mLifecycleRegistry;
}
}
因此,我们需要来分析LifecycleRegistry的addObserver方法
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
// 判断状态
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
// 这里将LifecycleBoundObserver又进行了一次包装
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
// 然后保存到map中
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
if (previous != null) {
// 同样的道理,如果缓存存在,直接返回
return;
}
// 从WeakReference中获取LifecycleOwner
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--;
}
分析上面的关键代码,也就是ObserverWithState的dispatchEvent方法
static class ObserverWithState {
State mState;
LifecycleEventObserver mLifecycleObserver;
ObserverWithState(LifecycleObserver observer, State initialState) {
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = getStateAfter(event);
mState = min(mState, newState);
// 关键代码,回调LifecycleBoundObserver的onStateChanged方法
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
}
当LifecycleBoundObserver的onStateChanged方法触发后就会触发父类的ObserverWrapper的activeStateChanged方法,activeStateChanged又会触发dispatchingValue方法,而最终会触发considerNotify方法,这个过程熟悉吧,我们上面分析LiveData原理的时候也分析到了,而且重点分析了dispatchingValue方法,当他传入null的时候会分发所有的观察者,当传入具体的ObserverWrapper时就会只会单独回调该ObserverWrapper,这里分析首次注册观察者的时候刚好对应的就是这种情况。
由上面分析得知,但我们首次调用LiveData的observer方法进行观察者注册的时候,其实是会触发LiveData的considerNotify方法触发的,这也就为粘性事件的分发提供了先天条件, 而必要条件就是mVersion > mLastVersion.
既然已经知道了原因,那么怎么解决呢? 我这里介绍2种方案:
1、因为每个LiveData都维护了一个mVersion,为了避免影响,我们在注册观察者的时候使用不同的LiveData对象就可以避免相互影响了.
2、自己维护LiveData和mVersion和ObserverWrapper的mLastVersion,这就需要我们重写LiveData了.
这里介绍方式2, 代码如下:
public class BaseLiveData<T> extends MutableLiveData<T> {
private int mVersion = -1; // 维护自己的mVersion
private boolean isSticky; // 控制是否允许粘性事件存在
public BaseLiveData(boolean isSticky) {
this.isSticky = isSticky;
}
public BaseLiveData() {
this(false); // 默认构造方法不支持粘性事件
}
// 重写数据监听的方法
@Override
public void observe(LifecycleOwner owner, Observer<? super T> observer) {
if (isSticky) {
// 默认的注册方式就是支持粘性事件的
super.observe(owner, observer);
} else {
// 走下面的方式就是屏蔽粘性事件的
super.observe(owner, new WrapperObserver<T>(observer, BaseLiveData.this));
}
}
// 重写属性发送的方法
@Override
public void setValue(T value) {
super.setValue(value);
mVersion++;
}
@Override
public void postValue(T value) {
super.postValue(value);
mVersion++;
}
static class WrapperObserver<T> implements Observer<T> {
private int mLastVersion;
private BaseLiveData<T> mLiveData;
private Observer<? super T> mObserver; // 外部注册的观察者
public WrapperObserver(Observer<? super T> observer, BaseLiveData<T> liveData) {
mObserver = observer;
mLiveData = liveData;
// 这是关键,当WrapperObserver首次注册的时候让mLastVersion=mVersion,这样首次注册的时候就不会触发mObserver的onChanged了
mLastVersion = mLiveData.mVersion;
}
@Override
public void onChanged(T t) {
// 下面的操作其实是参考LiveData的considerNotify原理
if (mLastVersion >= mLiveData.mVersion) {
return;
}
// 更新mLastVersion
mLastVersion = mLiveData.mVersion;
// 回调出去
mObserver.onChanged(t);
}
}
}
下面写一个Demo来验证下,MainActivity布局如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_info"
android:layout_width="match_parent"
android:layout_height="45dp"
android:gravity="center"
android:textColor="#ff0000"
android:textSize="22sp" />
<Button
android:onClick="sendEvent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发送事件" />
<Button
android:onClick="showFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="加载Fragment" />
<FrameLayout
android:id="@+id/fl_content"
android:layout_width="match_parent"
android:layout_height="300dp" />
LinearLayout>
很简单,2个Button分别用来发送事件和加载Fragment, 然后TextView用来显示接收到的事件,FrameLayout用来显示Fragment.
来看看MainActivity代码:
public class MainActivity extends AppCompatActivity {
// 这里传入true,表示支持粘性事件
private static BaseLiveData<String> mLiveData = new BaseLiveData<>(true);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 监听事件
mLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String data) {
TextView textView = findViewById(R.id.tv_info);
textView.setText(data);
}
});
}
// 发送事件
public void sendEvent(View view) {
mLiveData.postValue("hello world");
}
// 添加fragment
public void showFragment(View view) {
getSupportFragmentManager().beginTransaction().replace(R.id.fl_content, new MyFragment()).commit();
}
public static class MyFragment extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
TextView textView = new TextView(getActivity());
textView.setTextSize(22f);
textView.setGravity(Gravity.CENTER);
textView.setTextColor(Color.BLUE);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 200));
return textView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
// 使用和MainActivity同一个LiveData来监听事件
mLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String data) {
TextView textView = (TextView) view;
textView.setText(data);
}
});
}
}
}
我们先来看看支持粘性事件的效果,也就是BaseLiveData构造方法传入true的情况:
可以看到点击发送数据的时候MainActivity显示了数据, 然后点击添加MyFragment,由于此时是支持粘性事件的,MyFragment的onViewCreated调用 mLiveData.observe的事件立马就收到了粘性事件,然后显示了数据.
现在我们来将BaseLiveData构造方法的参数去掉,使用无参数的构造方法,也就是不支持粘性事件的情况,看看效果图:
由此可见,我们的BaseLiveData是支持屏蔽粘性事件的.