【Android】LiveData 用法及源码解析
本文讲解 LiveData 用法,以及 LiveData 源码解析。
官方文档:https://developer.android.google.cn/topic/libraries/architecture/livedata
一句话介绍 LiveData :LiveData 是一种可观察的数据存储器类。
与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
为什么需要 LiveData:
- 能够保证数据和 UI 统一(跟 LiveData 采用观察者模式有关,LiveData 是被观察的,当数据有变化时它会通知 UI 界面来更新数据。)
- 减少内存泄漏(在 LiveData 中,能够感知到组件的生命周期,当组件的生命周期处于未激活状态或已经处于 Destroy 状态的时候,观察者就会被清理掉。)
- 当 Activity 停止时不会引起崩溃(因为 Stop 时就已经变成非激活状态,在 LiveData 分发数据的过程中此时这个组件是非激活状态,LiveData 就不会给它分发数据,其实在组件处于 Pause 时就已经不给他分发数据了,只有它再次 Resume 的时候会重新灌入数据。)
- 不需要额外的手动处理来响应生命周期的变化(因为它内部有观察生命周期 Lifecycle 的组件)
- 组件和数据相关的内容能实时更新(当组件从后台来到前台时,LiveData 能够将最新的数据通知组件,灌入到组件里面,保证了组件和数据相关的内容能够实时的更新。)
- 针对 Configuration Change 时,不需要额外的处理来保存数据(因为在屏幕发生改变时,ViewModel 不会变,当它重建的时候会取得上一次的 ViewModel ,ViewModel 对应的也是之前的 LiveData 。LiveData 中的数据没有变,自然的它在重建过程中 LiveData 数据会时时的再次通知到已经重建的新组件中。)
- 资源共享(通过继承 LiveData ,将类定义成单例模式,在该类封装一些监听系统属性变化,然后通知 LiveData 的观察者。)
注:本文使用 Kotlin 编写。
导入 LiveData 库:implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
一、用法
1. 自定义布局,一个 TextView ,两个 Button
<?xml version="1.0" encoding="utf-8"?>
2. 自定义 ViewModel 类,在 ViewModel 中改变 LiveData 数据的值。
class MainViewModel : ViewModel() { val TAG = "MainViewModel" val liveData = MutableLiveData() var stop = false fun start() { liveData.postValue(0) object : Thread() { override fun run() { while (!stop) { sleep(1000) val value = liveData.value liveData.postValue(value?.plus(1)) Log.d(TAG, "run: " + liveData.value.toString()) } } }.start() } fun stop() { stop = true }}
3. 在 Activity 里观察 LiveData
class MainActivity : AppCompatActivity() { lateinit var mainViewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java) mainViewModel.liveData.observe(this, Observer { tv_content.text = it.toString() }) btn_start.setOnClickListener { mainViewModel.start() } btn_stop.setOnClickListener { mainViewModel.stop() } }}
4. 执行程序,点击 Start Button ,每隔1s,数据会发生改变;点击 Stop Button ,线程关闭,数据不再发生改变。
二、源码解析
1. MutableLiveData 源码:
public class MutableLiveData extends LiveData { public MutableLiveData(T value) { super(value); } public MutableLiveData() { super(); } @Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); }}
MutableLiveData 是对 LiveData 的拓展。因为 LiveData 是一个 abstract 的 class ,并不能直接使用。
2. LiveData 类图:
观察上面的类图,它有两个实现类,一个是 MutableLiveData ,另一个是 MediatorLiveData 。内部包含了一个 LifecycleBoundObsOvserver ,它实现了 Lifecycle 的 Observer ,它里面的 Observer 进行了对组件生命周期的观察。所以 LiveData 才有了观察组件生命周期的能力。
LiveData 函数说明:
- observe() 观察函数
- setValue() 设置值,必须在主线程调用,直接去改变 UI 界面
- postValue() 设置值,主线程或子线程都可以使用,不需要手动切换线程
- getValue() 取值
- hasActiveObservers() 是否有激活状态下的组件
- hasObservers() 是否有观察者
- observeForever() 不管 Lifecycle 是不是激活状态,永远都去观察
- removeObserver() 移除观察者
- onActive() 激活回调
- onInactive() 解除激活回调,也就是非激活状态
实现了 LifecycleEventObserver 接口,用来观察组件生命周期。
<
大体流程:LiveData post 或 set value 的时候,首先通过 hasObservers 判断是否有观察者,如果没有就不进行分发,如果有就通过 onActive 遍历是否是激活状态,如果是激活状态就会去调用 <
3. LiveData.observe() 源码
public void observe(LifecycleOwner owner, 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);}
传进来的 owner 是 Activity 或 Fragment ,然后把 observer 观察者也传进来。
首先判断是否是 DESTROYED 状态,如果是就 return 。
然后会 new 一个 LifecycleBoundObserver ,用来处理生命周期。
把 wrapper put 到 mObservers 容器里面,这个容器是用来遍历用的。
owner 获取 getLifecycle ,添加生命周期观察者 addObserver 。
4. LiveData.postValue() 源码
protected void postValue(T value) { ... ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);}
因为它可以在子线程进行分发,所以它要 postToMainThread 到主线程去:
private final Runnable mPostValueRunnable = new Runnable() { @Override public void run() { ... setValue((T) newValue); }};
它最终调的还是 setValue() 。所以说 setValue() 是在主线程进行调用。
5. LiveData.setValue() 源码
protected void setValue(T value) { assertMainThread("setValue"); mVersion++; mData = value; dispatchingValue(null);}
在 set 或 post 时,它的 mVersion 会更新一下,内部的 mData 会被赋值新的 value 。
6. LiveData.dispatchingValue() 源码
void dispatchingValue(ObserverWrapper initiator) { // 判断是否正在进行分发动作,如果正在进行就直接 return 。 if (mDispatchingValue) { mDispatchInvalidated = true; return; } mDispatchingValue = true; // 执行 do while 循环 do { mDispatchInvalidated = false; if (initiator != null) { considerNotify(initiator); initiator = null; } else { // 遍历,通过 Map 进行存储 for (Iterator < Map.Entry < Observer < ?super T > , ObserverWrapper >> iterator = mObservers.iteratorWithAdditions(); iterator.hasNext();) { // 这里的 iterator.next() 对应的是 ObserverWrapper 。 considerNotify(iterator.next().getValue()); if (mDispatchInvalidated) { break; } } } } while ( mDispatchInvalidated ); mDispatchingValue = false;}
7. LiveData.considerNotify() 源码
private void considerNotify(ObserverWrapper observer) { // 判断是否是激活状态,如果是非激活状态直接 return 。 if (!observer.mActive) { return; } // 判断是否是激活状态,如果是非激活状态直接 return 。 if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } // 判断 当前版本 大于等于 LiveData 总的版本号,就不会继续分发。 if (observer.mLastVersion >= mVersion) { return; } // 把当前的 Version 赋值给 observer 。 observer.mLastVersion = mVersion; observer.mObserver.onChanged((T) mData);}
这个函数解释了 Activity 不会被重复回调的原因。
把 mData 传给当前的 observer 。比如我们的 MainActivity 里面的代码:
mainViewModel.liveData.observe(this, Observer { ...})
public interface Observer { void onChanged(T t);}
最终会回调到 Observer {} 里去执行 tv_content.text = it.toString() 。
如果本文对你有帮助,请点赞支持!!!
更多相关文章
- 一句话锁定MySQL数据占用元凶
- 关于android 数据库SQLite的使用日记
- 四大组件及Window简要运行时序图
- Android———ContentProvider理解与使用
- LibGDX学习-LibGDX基本框架
- 我的android 第24天 - ContentUris和ContentProvider
- Android(安卓)Service组件
- Android系统架构和四大组件
- Media-媒介(媒体、介质)【译】