前言
本章开始 LiveData 的讲解;
LiveData 是一种可观察的数据存储器类,与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件如(Activity、Fragment、Service)的生命周期。
这种感知能力确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者;
它既是观察者又是被观察者,充当着两个角色;
这样的一个状态流转,典型的数据驱动更新 UI;
基础使用
基础用法
我们先来声明一个 LiveData 变量
object MyLiveData { // 单例
// 懒加载
val info1: MutableLiveData<String> by lazy { MutableLiveData() }
}
这样,MyLiveData 中就持有了一个 LiveData 对象;
接下来声明观察者
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView : TextView = findViewById(R.id.tv_textview)
// 观察者
MyLiveData.info1.observe(this, {
textView.text = it // 更新UI
})
}
}
可以使用 lambda 的方式,也可以使用传统的完整写法:
MyLiveData.info1.observe(this, object: Observer<String> {
override fun onChanged(t: String?) {
textView.text = t // 更新UI
}
})
接下来,我们来触发改变;
MyLiveData.info1.value = "default" // setValue 主线程
也可以在子线程触发改变
thread {
Thread.sleep(3000)
MyLiveData.info1.postValue("三秒钟后,修改了哦") // postValue 子线程
}
这就是典型的数据驱动UI,通过 postValue 或者 setValue 修改数据,通过 observer 回调驱动 UI 更新;
LiveData 是可以平替 EventBus 的,也就是说,我们在 A 界面触发改变,B 界面是可以监听到数据变化并更新UI;
前台更新UI
我们接下来看一个比较特殊的例子,可以验证只有当我们界面可见的时候才会更新UI这个点
声明 LiveData
object MyLiveData { // 单例
// 这里为 data1 的MutableLiveData 懒加载初始化(懒加载:用到时才加载)
val data1 : MutableLiveData<String> by lazy { MutableLiveData() }
}
我们来声明一个 Service
class MyService : Service() {
override fun onBind(intent: Intent): IBinder ? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
thread {
for (x in 1..10000) {
Log.d("server", "服务器给推你推送消息啦(叮咚声响),消息内容是:${x}")
MyLiveData.data1.postValue("服务器给推你推送消息啦,消息内容是:${x}")
Thread.sleep(2000) // 2秒钟推一次
}
}
return super.onStartCommand(intent, flags, startId)
}
}
接着我们在 MainActivity 启动这个 Service,以及接收 LiveData 发送的消息
class MainActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
// 启动服务
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
startService(Intent(this, MyService::class.java))
Toast.makeText(MainActivity2@this, "推送服务器启动成功", Toast.LENGTH_SHORT).show()
}
// 观察者 只有在界面可见的情况下,才能做事情
MyLiveData.data1.observe(this, {
Log.d("server", "界面可见,说明用户在查看微信列表界面啦,更新消息列表UI界面:${it}")
Toast.makeText(this, "更新消息列表UI界面成功:${it}", Toast.LENGTH_SHORT).show()
})
}
}
使用 Log 和 Toast 是为了方便查看,运行之后,当界面退后台的时候 我们能收到 LiveData 发送过来的消息,但是并不会更新UI;
数据更新的时候,如果不在前台,那么就不更新,而是等 Observer 到了前台才更新,这是利用了 Lifecycle 的特性来实现的,即性能高,又避免程序崩溃。这是 Rxjava 不能很方便做到的,它能做到,但不是很方便。这就是为什么我们用 RxJava 还能再最后一步转成 LiveData 的格式;
数据粘性
所谓数据粘性,就是我先修改数据,后订阅,但是我依然可以收到变化后的数据;
class MainActivity3 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main3)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
// 跳转之前 修改数据
MyLiveData.value1.value = "我就是我,不一样的烟火1"
startActivity(Intent(this, MainActivity4::class.java))
}
}
}
然后我们定义 MainActivity4
class MainActivity4 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main4)
// 我后观察数据,居然能够收到前面修改的数据,这就是数据粘性
MyLiveData.value1.observe(this, {
Toast.makeText(this, "观察者数据变化:$it", Toast.LENGTH_SHORT).show()
})
}
}
原理篇
分为订阅和发送,我们先来看下订阅 observe
订阅
我们进入这个 observe 方法看下
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
...
// 三行核心代码
// 让传递进来的 observer 具备感知生命周期的能力
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 将 LifecycleOwner 和 LifecycleObserver 关联起来
owner.getLifecycle().addObserver(wrapper);
...
}
Observer 可以看到就是一个纯接口,是无法感知生命周期变化的,它并没有实现 LifecycleObserver 接口;
public interface Observer<T> {
/**
* Called when the data is changed.
* @param t The new data
*/
void onChanged(T t);
}
而是借助 LifecycleBoundObserver 来让 observer 有了感知生命周期变化的能力;我们进入看一下
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
// 核心逻辑1,判断是否是存活状态 onStart、onResume 则是存活状态 mActive = true
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// 核心逻辑2,
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
核心逻辑1,判断是否是存活状态 onStart、onResume 则是存活状态 mActive = true
核心逻辑2,我们在上一章的 Lifecycle 中,生命周期分发的时候,6 个状态都会调用到这个 onStateChanged 方法;
我们接着看下 activeStateChanged 这个方法
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
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);
}
}
onActive() 和 onInactive() 是两个扩展接口,可以告诉外界存活状态和不存活状态,外界根据这两个方法进行扩展即可;
我们接着来看下 dispatchingValue 方法
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
// 核心逻辑1
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 核心逻辑2
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
核心逻辑1 被 if(initiator != null) 包裹,可以看到 initiator 是外部传入,也就是 dispatchingValue(this) 说明这个 initator 一定不为 null 而我们一直在看的是 observe 订阅流程
所以:核心逻辑1 是订阅流程,核心逻辑2 是发送流程(setValue、postValue)
我们接着看下这个 considerNotify 方法;
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
// 核心逻辑1
observer.activeStateChanged(false);
return;
}
// 核心逻辑2
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 核心逻辑3
observer.mObserver.onChanged((T) mData);
}
核心逻辑1 是判断界面如果突然可见了,就重新调用 activeStateChanged 再走一遍流程;
核心逻辑2 是决定我们的 LiveData 到底是不是粘性的;
mLastVersion 是观察者的版本,它是 -1;
mVersion 是被观察者的版本,它是 0,因为我们只要一调用 setValue 或者 postValue 它的版本就会 ++;
因为不相等,所以才能执行到核心逻辑3,将数据分发给观察者;
发送
我们进入 setValue 看下:
@MainThread
protected void setValue(T value) {
mVersion++;
mData = value;
dispatchingValue(null);
}
可以看到,mVersion 先执行 ++,才执行 dispatchingValue 方法;这个 dispatchingValue 方法就是我们前面刚分析过的 dispatchingValue 方法,只不过这次我们进入的是 else 的逻辑,因为传入的是 null,要执行 for 循环逻辑
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
considerNotify 就是我们前面分析的 considerNotify 方法;
所以这也就能解释通粘性事件的原因了;
我们在 MainActivity3 中,通过 MyLiveData.value1.value = "我就是我,不一样的烟火1" 将 mVersion 通过 mVersion++ 修改为 0;
当我们打开 MainActivity4 的时候,通过 MyLiveData.value1.observe 触发订阅之后,由于 mVersion = 0,mLastVersion = -1,触发了粘性数据的 onChanged 方法,导致在 MainActivity4 中收到了消息;
粘性解决
public class LiveDataBusX {
// 存放订阅者
private Map<String, BusMutableLiveData<Object>> bus;
private static LiveDataBusX liveDataBus = new LiveDataBusX();
private LiveDataBusX() {
bus = new HashMap<>();
}
public static LiveDataBusX getInstance(){
return liveDataBus;
}
// 注册订阅者
public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type){
if(!bus.containsKey(key)){
bus.put(key, new BusMutableLiveData<Object>());
}
return (BusMutableLiveData)bus.get(key);
}
public static class BusMutableLiveData<T> extends MutableLiveData{
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
super.observe(owner, observer);
hook(observer);
}
private void hook(Observer<? super T> observer) {
try{
// 1.得到 mLastVersion
// 获取到 LivData 的类中的 mObservers 对象
Class<LiveData> liveDataClass = LiveData.class;
Field mObserversField= liveDataClass.getDeclaredField("mObservers");
mObserversField.setAccessible(true);
// 获取到这个成员变量的对象
Object mObserversObject = mObserversField.get(this);
// 得到 map 对象的 class 对象
Class<?> mObserversClass = mObserversObject.getClass();
// 获取到 mObservers对象的 get 方法
Method get= mObserversClass.getDeclaredMethod("get", Object.class);
get.setAccessible(true);
// 执行get方法
Object invokeEntry = get.invoke(mObserversObject, observer);
// 取到 entry 中的 value
Object observerWraper = null;
if(invokeEntry!=null && invokeEntry instanceof Map.Entry){
observerWraper = ((Map.Entry)invokeEntry).getValue();
}
if(observerWraper == null){
throw new NullPointerException("observerWraper is null");
}
// 得到 observerWraperr 的类对象
Class<?> supperClass = observerWraper.getClass().getSuperclass();
Field mLastVersion = supperClass.getDeclaredField("mLastVersion");
mLastVersion.setAccessible(true);
// 得到 mVersion
Field mVersion= liveDataClass.getDeclaredField("mVersion");
mVersion.setAccessible(true);
// mLastVersion = mVersion
Object mVersionValue = mVersion.get(this);
mLastVersion.set(observerWraper, mVersionValue);
} catch(Exception e) {
}
}
}
}
好了,LiveData 比较简单,今天就讲到这里吧~
欢迎三连
来到来了,点个关注点个赞吧,你的支持是我最大的动力