@TryLoveCatch
2022-10-25T14:18:51.000000Z
字数 27699
阅读 1396
android
Jetpack
LiveData
https://www.jianshu.com/p/8c15cadb638f
LiveData是Google推出的一系列的框架组件的其中一个,它是一个可以被观察的数据持有类,能够感知Activity、Fragment等组件的生命周期。
LiveData 可以和生命周期绑定,当 Lifecycle(例如 Activity、Fragment 等)处于活跃状态时才进行数据回调,并在 Lifecycle 处于无效状态(DESTROYED)时自动移除数据监听行为,从而避免常见的内存泄露和 NPE 问题
一个观察者去观察LiveData后,当观察者的生命周期处于STARTED或RESUMED状态时(即onStart()、onResume()、onPause()),LiveData的数据发生变化,则会通知观察者;若观察者处于其他状态,即使LiveData的数据发生变化,也不会发出通知。
所以说,LiveData可以做到仅在组件处于活跃状态时才进行更新UI的操作
https://www.jianshu.com/p/8c15cadb638f
dependencies {
//...
def lifecycle_version = "1.1.1"
//仅仅依赖LiveData
implementation "android.arch.lifecycle:livedata:$lifecycle_version"
}
google提倡LiveData配合ViewModel一起使用。
为了专注LiveData,这里先不用ViewModel,后面再补充说明如何跟ViewModel一起使用。直接看例子:
public class TestModel {
private MutableLiveData<String> status;
public MutableLiveData<String> getStatus() {
if (status == null)
status = new MutableLiveData<>();
return status;
}
}
MutableLiveData继承自LiveData,表示可变数据。
这里创建一个保存String类型数据的LiveData。
public class TestActivity extends AppCompatActivity {
private static final String TAG = "test";
private TextView mTextView;
private TestModel mTestModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
mTextView = findViewById(R.id.tv_test);
init();
}
private void init() {
//创建一个观察者去更新UI
final Observer<String> statusObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
Log.d(TAG, "onChanged: " + newName);
mTextView.setText(newName);
}
};
//创建TestModel对象
mTestModel = new TestModel();
//观察LiveData对象
//这里的this指的是LifecycleOwner,即LiveData会跟生命周期联系起来
mTestModel.getStatus().observe(this, statusObserver);
}
}
observe(),可以对LiveData进行监听,需要传递一个LifecycleOwner参数进去,这表示LiveData会跟生命周期联系起来。
observeForever(),只需传递一个观察者进去就行,这意味着它跟生命周期没有任何关系,可以持续的观察,只要数据发生变化,都会通知观察者回调onChanged()。
public class TestActivity extends AppCompatActivity {
private static final String TAG = "test";
private TextView mTextView;
private TestModel mTestModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
mTextView = findViewById(R.id.tv_test);
initVariable();
}
private void initVariable() {
//创建一个观察者去更新UI
final Observer<String> statusObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newName) {
Log.d(TAG, "onChanged: " + newName);
mTextView.setText(newName);
}
};
//创建TestModel对象
mTestModel = new TestModel();
//观察LiveData对象
//这里的this指的是LifecycleOwner,即LiveData会跟生命周期联系起来
mTestModel.getStatus().observe(this, statusObserver);
mTestModel.getStatus().setValue("onCreate");
}
@Override
protected void onStart() {
super.onStart();
mTestModel.getStatus().setValue("onStart");
}
@Override
protected void onResume() {
super.onResume();
mTestModel.getStatus().setValue("onResume");
}
@Override
protected void onPause() {
super.onPause();
mTestModel.getStatus().setValue("onPause");
}
@Override
protected void onStop() {
super.onStop();
mTestModel.getStatus().setValue("onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
mTestModel.getStatus().setValue("onDestroy");
}
}
一个完整的生命周期走下来,其输出结果为:
07-26 22:03:34.798 20995-20995/com.test.start D/test: onChanged: onStart
07-26 22:03:34.801 20995-20995/com.test.start D/test: onChanged: onResume
07-26 22:03:36.456 20995-20995/com.test.start D/test: onChanged: onPause
可以看到,只在onStart()、onResume()、onPause()时观察者才会收到数据更新的通知,其他状态下即使更新了数据也不会收到通知。
比如说定位,我们希望有观察者的时候,开启定位,没有观察者的时候,就可以停止定位,没必要一直获取定位点
public class TestLiveData extends LiveData<Location> {
private static TestLiveData sInstance;
private LocationUtil mLocationUtil;
//设计为单例模式
public static TestLiveData getInstance() {
if (sInstance == null) {
sInstance = new TestLiveData();
}
return sInstance;
}
private TestLiveData() {
//创建一个获取位置的对象
mLocationUtil = new LocationUtil();
}
@Override
protected void onActive() {
//开始获取位置信息
mLocationUtil.start(mLocationListener);
}
@Override
protected void onInactive() {
//停止获取位置信息
mLocationUtil.stop();
}
//创建一个位置监听器
private LocationListener mLocationListener = new LocationListener() {
@Override
public void onReceiveLocation(Location location) {
//接受到位置信息后,更新数据
setValue(location);
}
};
}
public class TestViewModel extends ViewModel {
private MutableLiveData<Integer> mNumLiveData= new MutableLiveData<>();
//通过Transformations.map()将Integer类型的值转换为String类型
private LiveData<String> mStrLiveData = Transformations.map(mNumLiveData, new Function<Integer, String>() {
@Override
public String apply(Integer name) {
return name + "";
}
});
//observe这个,获取Integer类型的数据
public MutableLiveData<Integer> getNumLiveData() {
return mNumLiveData;
}
//observe这个,获取string类型的数据
public LiveData<String> getStrLiveData() {
return mStrLiveData;
}
}
public class TestViewModel extends ViewModel {
private MutableLiveData<String> mutableLiveData1 = new MutableLiveData<>();
private MutableLiveData<String> mutableLiveData2 = new MutableLiveData<>();
private MutableLiveData<Boolean> liveDataSwitch = new MutableLiveData<>();
LiveData transformedLiveData= Transformations.switchMap(liveDataSwitch, new Function<Boolean, LiveData<String>>() {
@Override
public LiveData<String> apply(Boolean input) {
if (input) {
return mutableLiveData1;
} else {
return mutableLiveData2;
}
}
});
public MutableLiveData<String> getMutableLiveData1() {
return mutableLiveData1;
}
public MutableLiveData<String> getMutableLiveData2() {
return mutableLiveData2;
}
public MutableLiveData<Boolean> getLiveDataSwitch() {
return liveDataSwitch;
}
public MutableLiveData<Boolean> getTransformedLiveData() {
return transformedLiveData;
}
}
// 使用
getTransformedLiveData().observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable final String s) {
Log.d(TAG, "onChanged:" + s);
}
});
getLiveDataSwitch().postValue(false);
getMutableLiveData1().postValue("1111");
getMutableLiveData2().postValue("2222");
当liveDataSwitch的值为true时返回mutableLiveData1,否则返回mutableLiveData2,可以用来切换监听的liveData
MediatorLiveData继承自MutableLiveData,它可以将多个LiveData数据源集合起来,可以达到一个组件监听多个LiveData数据变化的目的。
当任何一个MutableLiveData数据发生变化时,MediatorLiveData都可以感知到。
public class TestViewModel extends ViewModel {
private MutableLiveData<String> mutableLiveData1 = new MutableLiveData<>();
private MutableLiveData<String> mutableLiveData2 = new MutableLiveData<>();
private MediatorLiveData liveDataMerger = new MediatorLiveData<String>();
liveDataMerger.addSource(mutableLiveData1, new Observer() {
@Override
public void onChanged(@Nullable String str) {
liveDataMerger.setValue(str)
}
});
liveDataMerger.addSource(mutableLiveData2, new Observer() {
@Override
public void onChanged(@Nullable Object str) {
liveDataMerger.setValue(str)
}
});
public MutableLiveData<String> getLiveDataMerger() {
return liveDataMerger;
}
public MutableLiveData<String> getMutableLiveData1() {
return mutableLiveData1;
}
public MutableLiveData<Boolean> getMutableLiveData2() {
return getMutableLiveData2;
}
}
// 使用
getLiveDataMerger().observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable final String s) {
Log.d(TAG, "onChanged:" + s);
}
});
getMutableLiveData1().postValue("1111");
getMutableLiveData2().postValue("2222");
MediatorLiveData相比于LiveData,主要是多了以下两个方法:
首先我们带着问题来看:
然后我们从使用方式入手,根据使用API来一步一步看一下内部是怎么实现的
LiveData 包含两个用于添加数据观察者(Observer)的方法,分别是
两个方法的区别对于外部来说只在于是否提供了生命周期安全的保障
observe(LifecycleOwner , Observer) 传入的 LifecycleOwner 参数意味着携带了 Lifecycle 对象,LiveData 内部就根据 Lifecycle 的生命周期事件的回调变化在合适的时机进行数据通知,并在 Lifecycle 对象处于 DESTROYED 状态时自动移除 Observer,这也是 LiveData 避免内存泄漏的最重要的一个点。
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//限定只能在主线程调用 observe 方法
assertMainThread("observe");
//当 Lifecycle 已经处于 DESTROYED 状态时,此时进行 observe 是没有意义的,直接返回
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//根据传入参数构建一个新的代理 Observer
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//将 observer 作为 key,wrapper 作为 value 进行存储
//当 mObservers 不包含该 key 时,调用 putIfAbsent 会返回 null
//当 mObservers 已包含该 key 时,调用 putIfAbsent 不会存储 key-value,并会返回之前保存的 value
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
//走到此步,说明之前 LiveData 内部已经持有了 observer 对象,且该 observer 对象已经绑定了其它的 LifecycleOwner 对象
//此时直接抛出异常
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
//observer 之前已经传进来过了,此处直接返回
return;
}
owner.getLifecycle().addObserver(wrapper);
}
上面的代码使用到了 LifecycleBoundObserver,它是抽象类 ObserverWrapper 的实现类。
ObserverWrapper 用于包装外部传进来的 Observer 对象,为子类定义好特定的抽象方法和共用逻辑,主要是提供了共用的状态分发函数。
private abstract class ObserverWrapper {
//外部传进来的对 LiveData 进行数据监听的 Observer
final Observer<? super T> mObserver;
//用于标记 mObserver 是否处于活跃状态
boolean mActive;
//用于标记 Observer 内最后一个被回调的 value 的新旧程度
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<? super T> observer) {
mObserver = observer;
}
//用于获取当前 Lifecycle 是否处于活跃状态
abstract boolean shouldBeActive();
//用于判断 mObserver 是否和 LifecycleOwner(即 Lifecycle)有绑定关系
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
//移除 mObserver
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;
//判断当前 LiveData 所有的 Observer 是否都处于非活跃状态
boolean wasInactive = LiveData.this.mActiveCount == 0;
//更新 LiveData 当前所有处于活跃状态的 Observer 的数量
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
//如果 LiveData 处于活跃状态的 Observer 数量从 0 变成了 1,
//则回调 onActive 方法
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
//如果 LiveData 处于活跃状态的 Observer 数量从 1 变成了 0,
//则回调 onInactive 方法
onInactive();
}
if (mActive) {
//如果 mObserver 变成了活跃状态,则向其回调新值
dispatchingValue(this);
}
}
}
主要是activeStateChanged(boolean newActive)方法:
boolean wasInactive = LiveData.this.mActiveCount == 0
,这个LiveData.this.mActiveCount
是当前LiveData里面处于活跃状态的Observer个数,所以wasInactive判断是当前整个LiveData是否有活跃状态的Observer,true表示所有Observer都处于非活跃状态,false表示至少有一个Observer处于活跃状态LiveData#onActive()
,回调告知整个LiveData处于活跃LiveData#onInactive()
,回调告知整个LiveData处于不活跃LiveData#dispatchingValue(this);
,注意传入的参数值是this所以ObserverWrapper#activeStateChanged
主要做了两件事:
LiveData#mActiveCount
来判断整个LiveData的活跃状态,不活跃 -> 活跃回调LiveData#onActive()
,活跃 -> 不活跃 回调LiveData#onInactive()
调用大概有三个地方:
ObserverWrapper 一共有两个子类:LifecycleBoundObserver 和 AlwaysActiveObserver,两者的差别就在于是否和生命周期相绑定。
LifecycleBoundObserver,它是抽象类 ObserverWrapper 的实现类,它也实现了 GenericLifecycleObserver或者LifecycleEventObserver 接口,从而可以收到 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() {
//只有当 Lifecycle 的当前状态是 STARTED 或者 RESUMED 时
//才认为 Lifecycle 是处于活跃状态
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
//LifecycleEventObserver 的实现方法
//当 Lifecycle 的生命周期状态发生变化时就会调用此方法
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
//如果 Lifecycle 已经处于 DESTROYED 状态了,则主动移除 mObserver
//这就是 LiveData 可以避免内存泄露最重要的一个点
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
//移除 mObserver
mOwner.getLifecycle().removeObserver(this);
}
}
ObserverWrapper#activeStateChanged
,这个上面已经说过了observeForever() 函数本身不会考虑外部所处的生命周期状态,只要数据发生变化时就会进行数据回调,因此 observeForever()函数是非生命周期安全的
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
//限定只能在主线程调用 observe 方法
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
//会走到这一步,是因为之前已经先用该 observer 对象调用了 observe(LifecycleOwner,Observer)
//这里直接抛出异常
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
//如果之前已经添加过 observer 对象了的话,则直接返回
return;
}
//主动触发 activeStateChanged 函数,因为当前 LiveData 可能已经被设置值了
wrapper.activeStateChanged(true);
}
observe(LifecycleOwner,Observer)
方法,则直接抛出异常。因为如果允许 observer 同时调用observeForever()
和 observe()
函数,则当数据发生变化时,这可能会造成 Lifecycle 处于 DESTROYED 状态时还进行了数据回调,而这破坏了 observe(LifecycleOwner,Observer) 所期望的生命周期安全ObserverWrapper#activeStateChanged(true)
,不需要关系生命周期回调,直接传入trueAlwaysActiveObserver,它也是抽象类 ObserverWrapper 的实现类,其 shouldBeActive()返回值固定为 true,意味着只要有数据变化都会进行回调。
所以使用 observeForever() 函数一定要在过后主动移除 Observer,避免内存泄露和 NPE
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
//使其固定返回 true,则意味着只要有数据变化就都进行数据回调
return true;
}
}
removeObserver 的方式一共有两种,逻辑都比较简单
//移除指定的 Observer 对象
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
removed.detachObserver();
removed.activeStateChanged(false);
}
//通过循环遍历移除所有和特定 LifecycleOwner 绑定的 Observer 对象
@SuppressWarnings("WeakerAccess")
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
assertMainThread("removeObservers");
for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
if (entry.getValue().isAttachedTo(owner)) {
removeObserver(entry.getKey());
}
}
}
更新 LiveData 的值的方法一共有两个,分别是:
private volatile Object mData;
private int mVersion;
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
//更新当前 value 的版本号,即 value 的新旧程度
mVersion++;
mData = value;
dispatchingValue(null);
}
dispatchingValue(null)
,跟之前说的ObserverWrapper#activeStateChanged()
不同,这里调用的时候,传入参数为null。dispatchingValue() 这个被提到了很多次了
//用于标记当前是否正处于向 mObservers 发布 value 的过程
private boolean mDispatchingValue;
//用于标记当前正在发布的 value 是否已经失效
//在 value 还未向所有 Observer 发布完成的时候,新 value 已经到来,此时旧 value 就是处于失效状态
@SuppressWarnings("FieldCanBeLocal")
private boolean mDispatchInvalidated;
//initiator 为 null 则说明需要遍历回调整个 mObservers
//initiator 不为 null 则说明仅回调 initiator 本身
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
//如果 mDispatchingValue 为 true,说明当前正处于向 mObservers 发布 mData 的过程中
//而 dispatchingValue 方法只会在主线程进行调用,所以会出现 mDispatchingValue 为 true 的情况
//说明 Observer 的 onChanged 方法内部又主动向 LiveData setValue
//则将 mDispatchInvalidated 置为 true,用于标明有新值到来,正在回调的值是已经过时的了
mDispatchInvalidated = true;
return;
}
//用于标记当前正处于向 mObservers 发布 mData 的过程中
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) {
//如果 mDispatchInvalidated 为 true,则中断继续遍历过程
//用新值来重新循环一遍
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
dispatchingValue(ObserverWrapper)
关于这个入参有两种情况: do..while
呢? 这里,我有一个疑惑:
从逻辑上看 dispatchingValue() 函数只会在主线程进行调用,那么 dispatchingValue() 一定是会在执行完毕后才被再次执行,不存在多线程同时调用的情况,那么此时 mDispatchingValue 和 mDispatchInvalidated 两个变量就没有存在的必要了吧
private void considerNotify(ObserverWrapper observer) {
//如果 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.
//此处判断主要是为了照顾 LifecycleBoundObserver
//由于 Lifecycle 有可能状态值 State 已经切换到了非活跃状态,但 LifecycleBoundObserver 还未收到事件通知
//所以为了避免意外情况,此处主动检查 observer 的活跃状态并判断是否需要更新其活跃状态
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
//根据 observer 本部的 value 版本号 mLastVersion 来决定是否需要向其进行回调
//为了避免重复向某个 observer 回调值,所以此处需要判断下
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
ObserverWrapper
处于非活跃状态,直接returnLifecycleBoundObserver
还未收到事件通知,所以主动调用一下Lifecycle 的方法,来判断是否处于活跃状态ObserverWrapper#mLastVersion
和LiveData#mVersion
,来判断是否需要分发数据ObserverWrapper#Observer#onChanged()
postValue(T) 函数不限定调用者所在线程,不管是主线程还是子线程都可以调用,因此是存在多线程竞争的可能性的,postValue(T) 函数的重点旧在于需要理解其从子线程切换到主线程之间的状态变化
@SuppressWarnings("WeakerAccess") /* synthetic access */
final Object mDataLock = new Object();
@SuppressWarnings("WeakerAccess") /* synthetic access */
//mPendingData 的默认值
//当 mPendingData 等于 NOT_SET 时说明当前 LiveData 没有值需要通过 postValue 回调
static final Object NOT_SET = new Object();
volatile Object mPendingData = NOT_SET;
//用于在主线程对值进行回调
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
//通过加锁可以确保 newValue 指向的是当前最新值
newValue = mPendingData;
//重置 mPendingData
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};
protected void postValue(T value) {
boolean postTask;
//加锁以保证 mPendingData 值能够一直指向最新值
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
//如果 postTask 为 false,则说明当前有旧值需要通过 postValue 进行回调
//因为 postValue 可以在子线程调用,而 Observer 的 onChanged(value) 方法肯定是要在主线程被调用
//从子线程切到主线程之间是有段时间间隔的
//等到 mPostValueRunnable 真正执行时让其直接发送最新值 mPendingData 即可,所以此处直接返回
if (!postTask) {
return;
}
//向主线程发送一个 runnable,主要是为了在子线程调用 postValue,在主线程进行值回调
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
调用线程:
主线程:
所以当多个线程同时调用,在postTask为false,直接return
的时候,其实是会导致丢值的。在单个线程连续调用的时候,也会导致这个问题,为什么?因为调用Handler#post()
,会延迟调用,所以也会导致这个问题。
LiveData 的 setValue() 和 postValue() 方法的访问权限都是 protected,因此我们在日常开发中基本都是使用其子类
MutableLiveData 的源码很简单,只是将 setValue() 和 postValue() 方法的访问权限提升为了 public,从而让外部可以直接调用这两个方法:
public class MutableLiveData<T> extends LiveData<T> {
/**
* Creates a MutableLiveData initialized with the given {@code value}.
*
* @param value initial value
*/
public MutableLiveData(T value) {
super(value);
}
/**
* Creates a MutableLiveData with no value assigned to it.
*/
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
MediatorLiveData 是 MutableLiveData 的子类,可以添加多个LiveData数据源,监听这个多个LiveData,在他们的Observer回调的时候,调用MediatorLiveData自己的setValue来通知自己的Observer,具体例子可以看上面关于MediatorLiveData的使用例子
private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();
@MainThread
public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
Source<S> e = new Source<>(source, onChanged);
Source<?> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
//走到这一步,说明之前已经传进来过同个 source 对象
//但当时传的 Observer 对象与本地传递的 Observer 对象不是同一个
//直接抛出异常
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
//走到此步,说明之间已经用相同的 source 和 onChanged 对象调用过 addSource 方法
//所以直接返回
return;
}
//如果 MediatorLiveData 当前有处于活跃状态的 Observer 对其进行监听
//则调用 Source 对象的 plug() 函数
if (hasActiveObservers()) {
e.plug();
}
}
MediatorLiveData的源码其实很类似于LiveData,最重要的是增加了addSource()和removeSource():
Source#plug()
//移除对数据源的监听行为
@MainThread
public <S> void removeSource(@NonNull LiveData<S> toRemote) {
Source<?> source = mSources.remove(toRemote);
if (source != null) {
source.unplug();
}
}
代码很简单:
private static class Source<V> implements Observer<V> {
final LiveData<V> mLiveData;
final Observer<? super V> mObserver;
int mVersion = START_VERSION;
Source(LiveData<V> liveData, final Observer<? super V> observer) {
mLiveData = liveData;
mObserver = observer;
}
//对外部数据源 mLiveData 进行监听
void plug() {
mLiveData.observeForever(this);
}
//移除对外部数据源 mLiveData 的监听
void unplug() {
mLiveData.removeObserver(this);
}
@Override
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
}
observeForever()
,所以有两个后果 removeObserver()
,避免出现其他问题所以虽然提供了unplug()
,但是如果使用者没有调用呢,怎么能保证unplug()
一定被调用呢?
MediatorLiveData
复写了LiveData
的onActive()
和onInactive()
:
@CallSuper
@Override
protected void onActive() {
for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
source.getValue().plug();
}
}
@CallSuper
@Override
protected void onInactive() {
for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
source.getValue().unplug();
}
}
再说一下用法,根据用法我们来理解一下:
- MediatorLiveData#addSource(LiveData, Observer)
- MediatorLiveData#addSource(LiveData, Observer)
- MediatorLiveData#addSource(LiveData, Observer)
- MediatorLiveData#Observer(Observer)
为了描述简单,我们说MediatorLiveData为父LiveData,addSource添加的LiveData为子LiveData:
addSource()
来添加多个子LiveData,并进行监听observeForever()
来进行监听的,所以不具有生命周期安全observe(LifecycleOwner, Observer<T>)
来进行监听自己本身的数据变化Transformations 类是 lifecycle-livedata 库提供的一个工具类型的方法类,提供了三个静态方法用于简化对 MediatorLiveData 的使用,这里再来依次介绍下:
map(LiveData , Function) 函数用于简化向 MediatorLiveData 添加数据源的过程。大多数情况下,我们在使用 MediatorLiveData 时就是先将数据源类型 X 转换我们的目标数据类型 Y,然后再通过 setValue(Y) 进行数据回调。map 函数将这个数据类型转换过程抽象为了接口 Function,将 setValue(Y) 过程隐藏在了 map 函数内部
@MainThread
@NonNull
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
public interface Function<I, O> {
/**
* Applies this function to the given input.
*
* @param input the input
* @return the function result.
*/
O apply(I input);
}
switchMap,可以用来切换不同的子LiveData
@MainThread
@NonNull
public static <X, Y> LiveData<Y> switchMap(
@NonNull LiveData<X> source,
@NonNull final Function<X, LiveData<Y>> switchMapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
//先内部构建一个 MediatorLiveData,然后将 source 作为其数据源
result.addSource(source, new Observer<X>() {
//缓存每次的请求结果
LiveData<Y> mSource;
@Override
public void onChanged(@Nullable X x) {
//触发外界根据请求值 x 获得 LiveData 结果值的逻辑
//对应上面例子的 getUsersWithNameLiveData 方法
//这个过程是惰性的,即只有数据源 source 发生了变化才会触发请求
LiveData<Y> newLiveData = switchMapFunction.apply(x);
if (mSource == newLiveData) {
//如果 newLiveData 之前已经拿到了,则不必重复监听其回调结果
//直接返回即可
return;
}
if (mSource != null) {
//新值到来,移除对旧值的监听
result.removeSource(mSource);
}
mSource = newLiveData;
if (mSource != null) {
result.addSource(mSource, new Observer<Y>() {
@Override
public void onChanged(@Nullable Y y) {
//等到拿到了getUsersWithNameLiveData 的请求结果后
//就将结果值回调出去
result.setValue(y);
}
});
}
}
});
return result;
}
distinctUntilChanged() 函数用于过滤掉连续重复的回调值,只有本次的回调结果和上次不一致,本次的回调值才被认为是有效的
@MainThread
@NonNull
public static <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) {
final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>();
outputLiveData.addSource(source, new Observer<X>() {
//用于是否是第一次收到回调值
boolean mFirstTime = true;
@Override
public void onChanged(X currentValue) {
final X previousValue = outputLiveData.getValue();
//等式成立的条件一共有三种,满足其一即可
//1. 是第一次收到回调值,即 mFirstTime 为 true
//2. 上次的回调值为 null,本次的回调值不为 null
//3. 上次的回调值不为 null,且与本次的回调值不相等
if (mFirstTime
|| (previousValue == null && currentValue != null)
|| (previousValue != null && !previousValue.equals(currentValue))) {
mFirstTime = false;
outputLiveData.setValue(currentValue);
}
}
});
return outputLiveData;
}
感觉LiveData的源码相比Lifecycle,比较清晰简单
https://juejin.cn/post/6903096576734920717
https://tech.meituan.com/2018/07/26/android-livedatabus.html
livedata的粘性问题
使用SingleLiveEvent,虽然解决了粘性的问题,但是只支持单个观察者
还有一个问题,如果当前view不可见,那么只会调用setValue的,但是不会通知观察者,也就是不会调用onChanged,所以AtomicBoolean的值没有为置为false,在下次注册的时候,还是会通知一次
所以SingleLiveEvent只是解决了,多次注册时,非首次注册的观察者会获取到数据的问题,并没有解决首次注册的粘性问题
参考:https://github.com/JeremyLiao/LiveEventBus
https://yutiantina.github.io/2019/09/20/%E5%9F%BA%E4%BA%8ELiveData%E5%AE%9E%E7%8E%B0%E4%BA%8B%E4%BB%B6%E6%80%BB%E7%BA%BF%E6%80%9D%E8%B7%AF%E5%92%8C%E6%96%B9%E6%A1%88/
https://zhuanlan.zhihu.com/p/419512610
我们来回顾一下,之前说过LiveData有三个特性:
- 只在 Observer 至少处于 STARTED 状态时才能收到事件通知。Activity 只有在 onStart 方法后且 onPause 方法前才能收到事件通知
- LiveData 是黏性的。假设存在一个静态的 LiveData 变量,且已经包含了数据,对其进行监听的 Activity 都会收到其当前值的回调通知,即收到了黏性消息。这个概念就类似于 EventBus 中的 StickyEvent
- 中间值可以被新值直接掩盖。当 Activity 处于后台时,如果 LiveData 先后接收到了多个值,那么当 Activity 回到前台时也只会收到最新值的一次回调,中间值直接被掩盖了,Activity 完全不会感受到中间值的存在
以上三点特性都是由于界面层的特点来决定的:
https://www.jianshu.com/p/8c15cadb638f
http://liuwangshu.cn/application/jetpack/5-livedata-theory.html
https://github.com/leavesC/AndroidGuide/blob/gitbook/jetpack/LiveData%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90.md
https://github.com/leavesC/AndroidGuide/blob/gitbook/jetpack/LiveData%E8%A1%8D%E7%94%9F.md