Android Jetpack之LiveData源码分析
Posted 笨鸟-先飞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack之LiveData源码分析相关的知识,希望对你有一定的参考价值。
LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activity、fragment 或 service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。
您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 activity 和 fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 activity 和 fragment 的生命周期被销毁时,系统会立即退订它们)。
LiveData 的优势:
- 确保界面符合数据状态
- 不会发生内存泄漏
- 不会因 Activity停止而导致崩溃
- 不再需要手动处理生命周期
- 数据始终保持最新状态
- 适当的配置更改
- 共享资源。
以上内容均来自官网,官网地址
通过之前的博客:LiveData的简单使用。我们了解了LiveData的基本使用。这里回顾一下
LiveData的简单实用(一般都是跟ViewModel一起实用)
public class LiveDataActivity extends AppCompatActivity
private TextView mTextContent;
//使用LiveData
private MutableLiveData<String> contentLiveData = new MutableLiveData<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_livedata_test);
mTextContent = findViewById(R.id.tv_content);
//设置 观察者
contentLiveData.observe(this, new Observer<String>()
@Override
public void onChanged(String s)
mTextContent.setText(s);
);
//点击按钮,改变内容
findViewById(R.id.btn_livedata_change).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
contentLiveData.setValue("内容改变了");
);
下面的源码分析中,有些情况会设计到Lifecycle()监控生命周期。有兴趣的可以看下:Android Jetpack之Lifecycle的使用及源码分析
下面,我们通过上面使用的步骤,来分析。LiveData内容都做了什么操作
一、设置observe()方法
添加观察者,并且我们无需关系,移除及内存泄露问题
下面看下源码
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
...
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
assertMainThread("observe");
//owner是Activity已经实现的(Lifecycle文章有说)
//如果owner的生命周期已经结束的话,直接返回。避免了内存泄露,甚至Crash
if (owner.getLifecycle().getCurrentState() == DESTROYED)
// ignore
return;
//wrapper包装类。里面主要是一些生命周期及版本的判断
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
//这里,我们看到添加观察者的时候。是把观察者做key,放到了一个Map里面
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;
//这里跟我们添加Lifecycle()一样,可以让wrapper监听owner生命周期,做一些判断
owner.getLifecycle().addObserver(wrapper);
看到这里,其实发现很简单,添加观察者,其实,就是在LiveData里面创建了一个Map,把观察者存进去。
Map的值是个包含了owner(这里就是Activity,方便理解)和观察者observer的封装类。
二、分析通过set/postValue()改变内容
下面,我们看看LiveData的setValue()方法,是怎么把值传递过去的
public class MutableLiveData<T> extends LiveData<T>
@Override
public void setValue(T value)
super.setValue(value);
这里调用了super.setValue()继续看
@MainThread
protected void setValue(T value)
assertMainThread("setValue");
//这里的版本,后面会说
mVersion++;
mData = value;
dispatchingValue(null);
这里做了2个事情:
1,把值赋值给mData
2,调用 dispatchingValue(null);
我们接着看下
void dispatchingValue(@Nullable ObserverWrapper initiator)
if (mDispatchingValue)
mDispatchInvalidated = true;
return;
mDispatchingValue = true;
do
mDispatchInvalidated = false;
//initiator这里通过上面知道,传递的是null。所以,走else
if (initiator != null)
considerNotify(initiator);
initiator = null;
else
//把所有观察者的Map,通过迭代器遍历
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); )
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated)
break;
while (mDispatchInvalidated);
mDispatchingValue = false;
这里,我们可以看到,dispatchingValue()方法就是,遍历观察者所在的Map,然后,调用considerNotify()方法。
看下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.
if (!observer.shouldBeActive())
observer.activeStateChanged(false);
return;
if (observer.mLastVersion >= mVersion)
return;
observer.mLastVersion = mVersion;
//通过上面一系列的判断,最终调用了观察者的onChanged方法。
observer.mObserver.onChanged((T) mData);
这里,我们可以看到通过一些列生命周期的判断,版本的判断,最终调用了观察者的onChange()方法。
到这里,我们就已经走通了,所有的调用流程。
postValue的全过程跟setValue类似。只不过是后面通过Handler切换到了主线程上
[未完成]
上面有一点东西,我们没有说,那就是观察者observer的mLastVersion跟数据的mVersion问题。这个也是造成粘性数据的原因。但是,它跟EventBus不同的是,EventBus是提供了粘性数据的开关,但是,它并没有。
问题:LiveData的数据倒灌/粘性数据问题。
场景:(列表–详情(修改数据)–返回并点击其它列表–再次进入详情)(使用ShareViewModel)
SingleLiveEvent(解决一次事件,只消费一次),当注册多个观察者后,只有一个会受到,非常容易出错。
UnPeek-LiveData 解决方案
以上是关于Android Jetpack之LiveData源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Android kotlin 系列讲解(进阶篇)Jetpack系列之LiveData
Android JetPack组件之LiveData的使用详解
Android Jetpack 技术内幕探索之 LiveData