//请求数据成功后,通知UI刷新界面
updateUI()
}
})

//请求数据
viewModel.loadData()
}
}

上面三层基本上就是一个网络请求的闭环,Repository负责从网络或者数据库中请求数据,ViewModel负责调用Repository的数据,并利用LiveData的postValue()/setValue()方法将数据的更新通知到UI层,UI则只需要注册一个LiveData的观察者,当所匹配的LiveData调用postValue()/setValue()时,就会收到onChange()的通知,去做更新UI的操作。

(此图来源网上)

LiveData遵循观察者模式,它的厉害之处不仅在于数据有变化时能及时通知UI,而且LiveData能够感知Activity、Fragment等组件的生命周期,随组件销毁而自动销毁,不用开发者去操心,极大的减少了内存泄漏的可能。

那LiveData是如何通信并且感知组件的生命周期的呢?

LiveData的通信原理

从上面例子可以知道LiveData的核心主要在于这两步,liveData.observe()以及liveData.postVa
lue(),一个是注册观察者,一个是发送通知。那么下面的解析就将这两个函数作为切入点。

1.LiveData.observe()

从liveData.observe()跟踪进去:

LiveData.java

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull 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);
    }

observe方法传有两个参数LifecycleOwner和Observer,LifecycleOwner是一个具有Android生命周期的类,一般传入的是Activity和Fragment,Observer是一个接口,内部存在void onChanged(T t)方法。

✅ 第一部分: observe内部一开始就存在一个生命周期的判断,

if (owner.getLifecycle().getCurrentState() == DESTROYED) {return;}

当组件生命周期已经Destroy了,也就没有必要再继续走下去,则直接return。在这里,LiveData对生命周期的感知也就慢慢显现出来了。

✅ 第二部分: 首先以LifecycleOwner和Observer作为参数创建了一个LifecycleBoundObserver对象,接着以Observer为key,新创建的LifecycleBoundObserver为value,存储到mObservers这个map中。在后面LiveData postValue中会遍历出该map的value值ObserverWrapper,获取组件生命周期的状态,已此状态来决定分不分发通知(这部分详情见“第二小节postValue()”)

那LifecycleBoundObserver是什么?

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;

LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}


}

从源码可以看到,LifecycleBoundObserver继承ObserverWrapper并且实现了LifecycleEventObserver的接口,LifecycleEventObserver是监听组件生命周期更改并将其分派给接收方的一个接口,而在LifecycleBoundObserver的构造函数中将observer传给了父类ObserverWrapper。LifecycleBoundObserver其实只是包裹着LifecycleOwner和Observer得一个类,其中的实现有点代理模式的味道。

✅ 第三部分: owner.getLifecycle().addObserver(wrapper)将新创建的LifecycleBoundObserver添加到Lifecycle中,也就是说这个时候观察者注册成功,当LifecycleOwner也就是组件的状态发生改变时,也会通知到所匹配的observer。

到这里,UI层viewModel.liveData.observe(this, object:Observer<String> { override fun onChanged(value: String) {} })注册观察者的内部解析也就大致清楚了。

2.postValue()

liveData.postValue()是作为一个发射方来通知数据改变,其内部又做了哪些工作?接下来就一探究竟。直接从postValue中最核心的部分在于将参数value赋值给了一个全局变量源码开始:

protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

postValue中首先将参数value赋值给了一个全局变量mPendingData,它的初始值为一个空对象,而mPendingData只是作为一个中间媒介来存储value的值,在后续的操作中会用到,我们就暂时先记住它。

在最后就是一个将线程切换到主线程的操作,主要看mPostValueRunnable的实现:

private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings(“unchecked”)
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);
}
};

在Runnable中,mPendingData赋值给了临时变量newValue,最后调用了setValue()方法。我们都知道LiveData发送通知可以使用PostValue或者SetValue,而他两的区别就在于,PostValue可以在任意线程中调用,而SetValue只能在主线程中,因为PostValue多了一步上面切换主线程的操作。

OK,接下来就是PostValue/SetValue最核心的部分。

@MainThread
protected void setValue(T value) {
assertMainThread(“setValue”);
mVersion++;
mData = value;
dispatchingValue(null);
}

void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
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) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}

在setValue中,参数value将值赋给了一个全局变量mData,而这个mData最后将通过mObserver.onChanged((T) mData);将需要修改的value值分发给了UI。最后调用传入一个null调用dispatchingValue方法。

由于dispatchingValue里的参数为null,也就顺理成章的走到了✅ 第二部分。else一进入就是迭代器在遍历mObservers,而mObservers在第一小节“1.LiveData.observe()”中说得很清楚,它作为一个map,存储了Observer和ObserverWrapper。通过遍历,将每个观察者所匹配的ObserverWrapper作为参数传给了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;
observer.mObserver.onChanged((T) mData);
}

而在considerNotify()中,先通过observer来获取组件生命周期的状态,如果处于非活动状态,则拒绝发起通知。在该方法的最后, observer.mObserver.onChanged((T) mData),是不是很熟悉,这就是UI层一开始就实现的接口,而就在这找到了最后的发送方。

小结

LiveData是如何通信的?就一句话,UI层注册好一个observer,就存储到一个存储着观察者的map中,直到开发者调用postValue/setValue则遍历该map,分发出observer的onChanged通知,在此过程中,都会监听组件的生命周期,并以此来判断所匹配的组件是否处于活动状态,否则直接return。

三、LiveData的粘性事件

发送消息事件早于注册事件,依然能够接收到消息的通知的为粘性事件

即先调用LiveData的postValue/setValue方法,后注册observe,依然能够收到onChange()的通知。从上面的分析可以知道,LiveData最后postValue是将通知分发给已经注册好的观察者,而LiveData的粘性事件是先发送后注册,那为什么也能够收到通知呢?是哪里分发了onChange()?

我们知道粘性事件是注册后就收到了通知,那么就可以以liveData.observe()为切入点,康康源码中的实现。

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {

owner.getLifecycle().addObserver(wrapper);
}

LiveData注册观察者,最核心在于owner.getLifecycle().addObserver(wrapper);addObserver是用来添加一个LifecycleObserver,当LifecycleOwner改变状态时,它会被通知。例如,如果LifecycleOwner处于State#STARTED状态,给定的观察者将收到Event#ON_CREATE、Event#ON_START事件。

而我们跟踪到它的实现类里面,

public class LifecycleRegistry extends Lifecycle {

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

if (previous != null) {
return;
}
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
ate(observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

if (previous != null) {
return;
}
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {

【Jetpack篇】LiveData取代EventBus,flutter安装相关推荐

  1. 【Jetpack篇】LiveData取代EventBus,安卓面试项目

    owner.getLifecycle().addObserver(wrapper); } observe方法传有两个参数LifecycleOwner和Observer,LifecycleOwner是一 ...

  2. LiveData vs EventBus?不,他们其实可以一起

    /   今日科技快讯   / 近日,据国外媒体报道,电动汽车厂商特斯拉的股价本周一再次大涨,延续上周4个交易日连续大涨的势头,CEO埃隆·马斯克的身价也因此而增至463亿美元,比马云和拼多多创始人黄峥 ...

  3. flutter安装及过程中遇到的问题解决

    首先附上一个学习文档 https://flutterchina.club/setup-windows/ 一.安装SDK,这里讲解的是windows(用linux的大佬多一点,应该不需要看我这一篇啦) ...

  4. 1. Flutter安装(Windows)

    目录 一.下载 系统要求 获取Flutter SDK 更新环境变量 运行 flutter doctor 安装采坑记录 1. 在github或者官网下载flutter sdk后,配置完环境变量运行flu ...

  5. MongoDB学习第一篇 --- Mac下使用HomeBrew安装MongoDB

    2019独角兽企业重金招聘Python工程师标准>>> MongoDB学习第一篇 --- Mac下使用HomeBrew安装MongoDB 0.确保mac已经安装了HomeBrew ( ...

  6. 嵌入式linux编译环境搭建,嵌入式Linux之旅——环境搭建篇之交叉编译工具的安装...

    在正式开始学习裸机程序的编写之前,我们还需要安装一下交叉编译工具.何为交叉编译工具?其实就是在x86的ubuntu主机上编译程序,并且可以运行在arm环境的编译工具.而gcc是本地编译工具,这个在我们 ...

  7. Mongodb学习(安装篇): 在centos下的安装

    安装篇 ###下载解压文件 [root@192 lamp]# wget http://fastdl.mongodb.org/linux/mongodb-linux-i686- 2.2.2.tgz ## ...

  8. Flutter安装、配置、初体验 windows 版

    作为一名合格的开发人员,我们应该积极地去拥抱新的事物,当然这个想法也不限于技术,加油! Flutter 了解一下 Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生 ...

  9. Flutter安装后出现HTTP host not reachable.

    Flutter安装好配置环境变量之后在cmd运行Flutter doctor出现如下 两个问题: HTTP host https://maven.google.com/ is not reachabl ...

最新文章

  1. Java的TheadLocal使用
  2. 正式进驻1410实验室!
  3. Linux磁盘管理与文件系统(实验详解,一看就懂)
  4. 计算机网络之数据链路层:4、流量控制和可靠传输机制(停止等待协议、后退N帧协议、选择重传协议)
  5. Ubuntu 终端不能输入中文,不能显示中文的解决办法
  6. centos7搭建superset数据平台
  7. C++11创建线程的三种方式
  8. 项目从.Net3.5转化到.Net4.0发生错误
  9. 芯片如何储存信息_手机上的你以为信息删了就彻底删除了?事情没那么简单
  10. 国外打工人分享如何如何通过销售excel电子表格赚到 28 万美元
  11. python基础--绘制棋盘图形
  12. 最小二乘法(Least square method)
  13. 读《小强升职记》总结
  14. 【5】SCI易中期刊推荐——计算机科学(中科院2区)
  15. python编程做联机游戏大全单机_手把手教你将单机游戏改造成对战网游(附详细教程)...
  16. 【U8+】总账期初余额开账按钮是灰色的
  17. 网络入门基础(网络布线)
  18. 掌上实验室V8系列教程(七)I2C应用 HP203B
  19. 克里金(Kriging)插值的原理与公式推导_转
  20. 为什么360浏览器兼容模式文档模式默认以ie7标准渲染

热门文章

  1. 搬书 hnust校赛
  2. 高中数学必修一二次函数与幂函数试题及答案
  3. python多进程优化_Python 的多进程,考虑到会发生死进程,如何收敛结束,安全又方便?...
  4. iMatrix平台的权限管理系统是一个基于角色的访问控制系统
  5. fluent支持python吗_Python与Fluent联合仿真设置
  6. 职中选什么专业好_职高毕业,迷茫中,选什么专业和学校好
  7. 夜来风雨声,样式知多少?——CSS
  8. 文佳夹操作之获取指定目录下的所有文件及文件夹
  9. 【渝粤题库】陕西师范大学152205 西方行政学说史 作业(专升本)
  10. e讯丨美国政府问责局(GAO)发布网安审计报告 提出美应对网安挑战的十条行动