概述
LiveData用法与源码分析
- LiveData定义和作用
- LiveData用法
- LiveData源码分析
- Observe
- setValue和postValue
- 总结
- 数据粘性(倒灌)分析
LiveData定义和作用
LiveData是一种可观察的数据存储器类。
LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。
这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
LiveData用法
一般地,LiveData会与ViewModel等Jetpack全家桶一起配合使用,这里只分析LiveData,就直接单独使用LiveData了。创建一个单例类,其中只有一个LiveData对象
object TestLiveData {
val mData: MutableLiveData<String> by lazy { MutableLiveData() }
}
class LiveDataActivity : AppCompatActivity() {
private val TAG = "LiveDataActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_live_data)
TestLiveData.mData?.observe(this, object : Observer<String> {
override fun onChanged(t: String?) {
Log.d(TAG, "t : $t")
}
})
TestLiveData.mData?.value = "old"
thread {
Thread.sleep(3000)
TestLiveData.mData?.postValue("new")
}
}
}
主线程使用setValue
,子线程使用postValue
来修改LiveData的值,最终onChanged
回调必在主线程执行。页面没在展示状态,不会回调onChanged
,只有在前台时,才会回调。
LiveData源码分析
Observe
首先我们先看一下observe
方法具体做了哪些事情
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
//首先判断了是否在主线程,非主线程直接抛出异常
assertMainThread("observe");
//通过LifecycleOwner获取Lifecycle对象然后获取Lifecycle 的State,
//如果是DESTROYED直接 return 了。忽略这次订阅
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
//把LifecycleOwner和Observer包装成LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//把观察者存入Map
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
//是否添加过的一些判断
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycle");
}
if (existing != null) {
return;
}
//形成订阅关系
owner.getLifecycle().addObserver(wrapper);
}
可以看到,被观察者即Activity/Fragment和观察者LifecycleBoundObserver
之间已经建立了订阅关系,LifecycleBoundObserver
我们后面再来分析。观察者的回调方法在何时执行,我们继续看后面的流程。
setValue和postValue
TestLiveData.mData?.value = "old"
thread {
Thread.sleep(3000)
TestLiveData.mData?.postValue("new")
}
setValue
和postValue
分别调用了MutableLiveData
中的setValue
和postValue
方法,MutableLiveData是LiveData的子类,里面只有这两个方法,这样的设计给用户提供了最简洁的调用方法,用户不需要了解复杂的LiveData类。我们继续跟进到父类中查看他们的具体实现。首先查看setValue
方法
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
调用了dispatchingValue
方法,参数传递的是null
,继续跟代码
void dispatchingValue(@Nullable ObserverWrapper initiator) {
...
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()
,由于我们传入的是null
,这里进入else
,从我们订阅方法保存的mObservers
中取出我们的观察者。我们先跟进一下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);
}
这里判断了mActive
状态,这个值就是Lifecycle
中的状态,具体可以查看我上一篇Lifecycle的文章。
最终调用了observer.mObserver.onChanged((T) mData)
方法,这个observer.mObserver
就是我们的Observer接口,然后调用它的onChanged
方法。到现在整个被观察者数据更新通知观察者这个流程就通了。接着我们再来看一下postValue
方法
protected void postValue(T value) {
...
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
我们可以看到,postValue
方法最后,调用了postToMainThread
方法,其实是切换到主线程去执行。具体如何实现的呢,我们继续跟进一下postToMainThread
方法
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
跟进以后可以看到,最终通过拿到主线程的Looper
,实例化一个handler
,切换到主线程,我们来看一下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);
}
};
看到这里一目了然了,postValue
最终也是调用的setValue
,后面的流程就和setValue
一样了。
我们回过来再看一下LifecycleBoundObserver
类
LifecycleBoundObserver
实现了LifecycleEventObserver
接口,这个接口中有一个onStateChanged
方法,被观察者生命周期变化时,会回调此方法,这也是Lifecycle
中的方法,可以通过我的上一篇Lifecycle的文章中查看。
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) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
这里依然在判断mActive
状态,当mActive
为true
时,调用了dispatchingValue()
方法,也就是setValue
时所调用的方法,区别就是此时传入了this
,这里的this
也就是LifecycleBoundObserver
,入参不为空,会进入if
,也调用considerNotify
方法,最终调用observer.mObserver.onChanged((T) mData)
方法
void dispatchingValue(@Nullable ObserverWrapper initiator) {
...
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;
}
总结
LiveData首先提供方法,让被观察者(Activity/Fragment)与观察者(Observer)建立联系。然后再提供setValue
和postValue
方法,设置数据,在Lifecycle的onStateChanged
方法回调时,查看mActive
状态,再回调onChange()
数据粘性(倒灌)分析
一般地,在使用LiveData时,我们都会先订阅,后setValue
,但如果我们先setValue
,后订阅,会发现我们之前setValue
的值也会回调onChange
,这就是数据粘性。那么造成数据粘性的原因是什么呢,我们来通过源码分析一下。
首先我们回到setValue
方法
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
如果未订阅,先调用setValue
,这里mVersion
默认-1,++后为0,mData
保存。继续跟进dispatchingValue
void dispatchingValue(@Nullable ObserverWrapper initiator) {
...
do {
...
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);
...
}
前面讲过,setValue
时,这个方法必进else
,由于还没有订阅,mObservers
中没有值,不会进入considerNotify
方法。当订阅成功并生命周期改变后,回调onStateChanged
,进入if
,调用considerNotify
方法,此时再次比较两个version
private void considerNotify(ObserverWrapper observer) {
...
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
由于之前setValue
时,mVersion
已经++,所以不满足observer.mLastVersion >= mVersion
,于是会回调onChange
,把之前setValue
时保存的mData
带过去。到此就真相大白啦~
Google这样设计的本意是,当页面重建时,我们不需要再重新发起请求,而可以收到LiveData推送来的数据,但是对于我们平时开发来说大部分时候时不需要这种效果,那么我们该如何去除粘性呢?下篇文章来写吧~链接在这里
最后
以上就是重要斑马为你收集整理的Jetpack-LiveData用法与源码分析LiveData定义和作用LiveData用法LiveData源码分析的全部内容,希望文章能够帮你解决Jetpack-LiveData用法与源码分析LiveData定义和作用LiveData用法LiveData源码分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复