网上关于DataBinding,ViewModel,LiveData文章很多,最近结合源码及相关实例分析了一下,本文结合LiveData的使用来对LiveData进行源码分析。
关于DataBinding的使用,可以参考之前的文章:
Android JetPack DataBinding分析
一.LiveData简介
LiveData 是一个可观察的数据持有者类。与常规 observable 不同,LiveData 是生命周期感知的,这意味着它尊重其他应用程序组件的生命周期,例如 activity,fragment。此感知确保 LiveData仅更新处于活动状态的应用组件观察者。
如果 Observer 类表示的观察者生命周期处于 STARTED
或 RESUMED
状态,则 LiveData 会将其视为活动状态。LiveData 仅通知处于活动状态的观察者更新信息。非活动状态的观察者不会收到有关数据更改的通知。
你可以注册与实现了 LifecycleOwner
接口的对象配对的观察者。此关系允许在相应 Lifecycle
对象的状态更改为 DESTROYED
时删除观察者。这对于 activity 和 fragment 特别有用,因为它们可以安全地观察 LiveData 对象而不用担心泄漏 - activity 和 fragment 在其生命周期被销毁时立即取消订阅。
二.LiveData使用
LiveData是一个抽象类,不能直接实例话,google为我们定义好了实现类MutableLiveData,可以通过MutableLiveData来创建不同类型的对象,结合代码来看一下:
a.基础功能
private MutableLiveData mLiveData = new MutableLiveData<>();
mLiveData.observe(this, new Observer() {
@Override
public void onChanged(String s) {
Toast.makeText(HookActivity.this, "receive message is " + s,Toast.LENGTH_SHORT).show();
}
});
mLiveData.setValue("test lifecycle observe");
通过以上可以看到,使用起来还是比较简单的,先创建一个MutableLiveData对象,执行observe()方法,传入当前UI实现类(A/F)的对象引用和observer(监听data变化),执行setValue()来更新MutableLiveData的值。
b.进阶功能
UI内实现了对某个LiveData的监听,当UI处于后台后,此时LiveData的值进行了更新,那应该如何处理呢?结合代码来看一下:
private void testDataObserverLifecycle() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
mLiveData.postValue("test lifecycle observe");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
以上方法可以看到,是启动一个线程,然后在3s后对LiveData进行了值更新,注意一下,postValue()是在非UI线程执行的值更新调用方法,当我们在执行以上方法后,将当前界面切换到后台,3s之后再切换回来,发现会弹出toast提示。
结论:LiveData会监听UI的生命周期变化,当处于前台后,会将值变化通知到UI。
c.全局功能
通过以上可以看到,当LiveData发生变化后,UI处于后台时,是不会收到值更新的,但是当返回前台后,会立刻收到值变化通知UI,那如果LiveData作为一个全局的变量,新的UI(A/F)启动后监听该LiveData会怎样呢?结合代码来看一下:
①.定义全局变量
定义一个单例模式的类,里面定义一个HashMap来存储MutableLiveData,通过key来获取,如果map中存在,就返回;否则创建,然后存入map。
public final class LiveDataBus {
private final Map> bus;
private static class InstanceHolder {
public static LiveDataBus sInstance = new LiveDataBus();
}
private LiveDataBus() {
bus = new HashMap<>();
}
public static synchronized LiveDataBus getInstance() {
return InstanceHolder.sInstance;
}
public MutableLiveData with(String target, Class type) {
if (!bus.containsKey(target)) {
bus.put(target, new MutableLiveData<>());
}
return (MutableLiveData) bus.get(target);
}
}
②.创建LiveData
先在Activity1内使用对应key的变量,并更新值:
private void testData() {
new Thread(new Runnable() {
@Override
public void run() {
try {
LiveDataBus.getInstance().with("key_test", String.class).postValue("LiveDataBus test");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
③.使用LiveData
后在类Activity2内使用对应key的变量:
LiveDataBus.getInstance().with("key_test", String.class).observe(this,
new Observer() {
@Override
public void onChanged(String s) {
Toast.makeText(Activity2.this, "receive message is " + s,Toast.LENGTH_SHORT).show();
}
});
我们发现,会弹出Toast提示,也就是说后面创建新的UI内部使用该LiveData,也会收到回调,跟stick broadcast类似,后面注册该broadcast时,会立刻收到广播。
在对LiveData进行使用后,有了一定的了解,带着问题去看一下LiveData的源码。
三.LiveData源码分析
a.observe()
LiveData注册了LifecycleOwner(Activity/Fragment)生命周期的观察者,当Activity/Fragment生命周期发生变化后,LiveData会对生命周期状态进行判断,来确定是否需要通知LifecycleOwner进行逻辑更新,详情可参考Android Jetpack Lifecycle详解,注册逻辑如下:
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);
}
从上面可以看到:在进行observe()时,首先确保是主线程,如果LifeCycleOwner的生命周期是destroyed时,直接返回;然后将owner及observer封装成LifecycleBoundObserver,添加到mObservers里面,后续值发生变化时,会遍历回调;最后将wrapper添加到owner的lifecycle生命周期的观察者。
接下来看一下LifecycleBoundObserver的实现:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
.......
@Override
//判断owner是否处于active状态
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
//LifecycleEventObserver实现了LifecycleObserver,owner生命周期状态发生变化后的回调
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
//当owner生命周期状态发生变化后,看是否需要将数据更新到owner,如果从后台切换到前台后,会将最新数据更新到UI[每次执行setValue()后,都会保存最新的mData = value]。
activeStateChanged(shouldBeActive());
}
......
}
LifecycleBoundObserver实现了LifecycleEventObserver,owner有生命周期变化后,会回调onStateChanged()方法,当其生命周期变为DESTROYED后,会移除observer,这也就是为什么我们不需要手动 remove observer 的原因,此后LiveData发生变化后,不会更新到Activity/Fragment,即不会一直持有其引用,从而不会造成内存泄露;
当Activity/Fragment处于前台后,会将最新的数据更新到UI,逻辑如下:
void activeStateChanged(boolean newActive) {
......
if (mActive) {
dispatchingValue(this);
}
}
感知数据变化如下:
b.setValue()/postValue()
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
protected void postValue(T value) {
......
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
执行setValue()及postValue()后,会先更新mData为最新的value,然后执行dispatchingValue()。
c.dispatchingValue()
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;
}
通过以上可以看到,在执行dispatchingValue()后,会对参数进行判断,如果不为空,会单独调用considerNotify();如果为空,则会遍历调用considerNotify()。
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);
}
通过以上可以看到,在considerNotify()内部会最终调用observer.mObserver的onChanged()方法。
d.通知途径
以上可以看到,有两种途径会最终调用dispatchingValue():
1.setValue():调用dispatchingValue(null),会通知所有的observer,进而再调用considerNotify()进行更新。
2.A/F(LifeCycleOwner)的activeStateChanged():调用dispatchingValue(this),由于此处参数不为null,所以会单独回调监听该owner对应的observer。LiveData内部关联了LifecycleOwner(Activity/Fragment)生命周期相关的方法,当LifecycleOwner生命周期变化的时候都会回调onStateChanged()方法,然后会去调用activeStateChanged(),最后调用considerNotify()方法去执行数据变化回调。
接收事件流程:
以上就是对LiveData源码的分析,包括observe()及其内部封装、setValue()后执行dispatchValue()、considerNotify()最终执行observer的onChanged()进行通知及数据更新。
四.LiveData粘性去除
以上实例可以看到,LiveData可以作为全局变量来使用,具有粘性的功能,如果不需要粘性功能,需要怎么处理呢?先看一下considerNotify()方法的内部实现:
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);
}
如果修改内部执行逻辑的话,可以通过hook来实现,内部有3处可以执行return,但是唯一可以hook的就是来使mLastVersion==mVersion,来使条件满足执行return,看一下实现方式:
public final class LiveDataBus {
......
public MutableLiveData with(String target, Class type) {
if (!bus.containsKey(target)) {
bus.put(target, new BusMutableLiveData<>());
}
return (MutableLiveData) bus.get(target);
}
private static class BusMutableLiveData extends MutableLiveData {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
super.observe(owner, observer);
try {
//通过设置mLastVersion = mVersion在执行considerNotify()时返回,消除粘性
hook(observer);
} catch (Exception e) {
e.printStackTrace();
}
}
private void hook(@NonNull Observer> observer) {
Class> liveDataClass = LiveData.class;
try {
Field mObserversField = liveDataClass.getDeclaredField("mObservers");
mObserversField.setAccessible(true);
Object mObservers = mObserversField.get(this);
Class> mObserversClass = mObservers.getClass();
Method getMethod = mObserversClass.getDeclaredMethod("get", Object.class);
getMethod.setAccessible(true);
Object entry = getMethod.invoke(mObservers, observer);
Object observerWrapper = ((Map.Entry) entry).getValue();
Class> observerClass = observerWrapper.getClass().getSuperclass();
Field mLastVersionField = observerClass.getDeclaredField("mLastVersion");
mLastVersionField.setAccessible(true);
Field mVersionField = liveDataClass.getDeclaredField("mVersion");
mVersionField.setAccessible(true);
Object mVersionValue = mVersionField.get(this);
mLastVersionField.set(observerWrapper, mVersionValue);
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
以上可以看到,自定义类继承MutableLiveData类,在observe()后,执行hook(),将observer的mLastVersion的值设成跟mVersion一致就可以了。
五.LiveData 的优点:
a.确保你的 UI 符合你的数据状态
LiveData遵循观察者模式,状态更改时LiveData会通知 Observer对象,观察者可以在每次数据变化时更新UI。
b.没有内存泄漏
观察者绑定到 Lifecycle 对象,并在其相关生命周期被销毁后自行清理。
c.不会因为 activity 停止而发生崩溃
如果观察者的生命周期处于非活动状态(例如,activity 在后台堆栈中),则它不会接收任何 LiveData 事件。
d.不再需要手动处理生命周期
UI 组件只是观察相关数据,不会停止或恢复观察。LiveData自动管理所有这些,因为它在观察时意识到相关的生命周期状态变化。
e.始终保持最新数据
如果生命周期变为非活动状态,它将在再次变为活动状态时接收最新数据。例如,后台 activity 在返回前台后立即接收最新数据。
f.适当的配置更改
如果由于配置更改(例如设备旋转)而重新创建 activity 或 fragment,则会立即接收最新的可用数据。
g.共享资源
可以使用单例模式扩展 LiveData 对象以包装系统服务,以便可以在应用程序中共享它们。LiveData 对象连接到系统服务一次,然后任何需要该资源的观察者只需观察 LiveData 对象。
以上是对LiveData的使用及源码分析,详细理解需要重点关注LiveData这个类。