0
点赞
收藏
分享

微信扫一扫

Android mvvm 之 LiveData 的原理,腾讯Android面试题

往复随安_5bb5 2022-04-13 阅读 69

前言

“金三银四”再过几天就到了,又到了一年一度的大型**“程序猿跳槽大会”**。作为大龄IT从业者的我们,每到这个时候就会想起年轻时的自己,为了能搞定面试官,通宵背题库,背定义,四处收集面试真题…每次都准备的满满当当,可一到了面试的时候,就会发现与自己预想的完全不一样。

直到后来经历了这么多年,自己也从曾经的应聘者变成了面试者,才终于明白这样的道理:面试官远远要比应聘者狡猾得多。

不按套路出牌是面试官的“基本素养”,多年的工作经验使他们完全不需要提前准备一些特定的题目和答案,随便的几个问题,就可以通过回答对其了解个大概。

我与几个面试官朋友,从面试官的角度进行分析,帮助应聘者了解面试官的想法,揭秘大厂面试官内心:我该如何“刁难”面试者。

注意图示,一个 User-defined Observer 必须和一个 LifecycleOwner 唯一绑定,否则将无法订阅。试想,如果一个 Observer 同时绑定两个 LifecycleOwner:L1 和 L2,假如 L1 处于 RESUMED 的状态,而 L2 处于 DESTROYED 的状态,那么 LiveData 将无所适从:如果遵循 L1 的状态,将变化通知给 Observer,则更新 L2 会出错;如果遵循 L2 的状态,不将变化通知给 Observer,则 L1 得不到及时更新。

[](()2.3 多对多的双向订阅网

LiveData 和 LifecycleOwner 之间因为需要相互观察对方状态的变化,从而需要实现双向订阅;同时,为了支持良好的可扩展能力,各自都维护了一个观察者列表,形成一个多对多的双向订阅网络:

bidirection_subscribes

我们看到一个 LiveData 是可以同时向多个 LifecycleOwner 发起订阅的,所以,LiveData 本身其实并不实际维护一个激活状态,真正的激活状态维护在 LifecycleOwner 的 User-defined observer 中。

[](()3 LiveData 的事件变化

LiveData 值更新之后的需要通知订阅者(观察者),其通知流程非常简单:

livedata_setvalue

其中,判断观察者是否激活,即判断 LifecycleOwner 是否处于 STARTED 或 RESUMED 状态,在 2.1 节中已有说明。

我们看一下关键的源代码:

// 入口

@MainThread

protected void setValue(T value) {

// 必须在主线程调用

assertMainThread(“setValue”);

//…省略非关键代码

// 设置新值并派发通知

mData = value;

dispatchingValue(null);

}

// 通知派发流程

void dispatchingValue(@Nullable ObserverWrapper initiator) {

//…省略非关键代码

// 遍历观察者列表

for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =

mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {

// 尝试通知观察者

considerNotify(iterator.next().getValue());

//…省略非关键代码

}

}

其中 LiveData.considerNotify() 在 2.1 节中已有说明。

[](()4 LifecycleOwner 的事件变化

对于 LifecycleOwner 来说,其变化的事件即为生命周期状态的变化。在 LifecycleOwner 的事件委托者 Lifecycle 看来,无论是发生了 ON_CREATE 事件还是 ON_START 事件,或是任何其它的事件,其事件的切换流程都是通用的。

换言之,只要 Lifecycle 接口的实现者实现这一通用切换流程,便只需给 LifecycleOwner 暴露一个切换入口,就能在 LifecycleOwner 的各个生命周期回调函数中调用这个入口就可以了。这样我们在 LifecycleOwner 中应该可以看到形如这样的流程(伪代码表示):

public class Activity/Fragment implements LifecycleOwner {

@Override

public onCrate() {

//…省略非关键代码

// 在 Jetpack 框架中,LifecycleImpl 被命名为 LifecycleRegistry

LifecycleImpl.handleLifecycleEvent(ON_CREATE);

}

@Override

public onStart() {

//…省略非关键代码

LifecycleImpl.handleLifecycleEvent(ON_START);

}

@Override

public onResume() {

//…省略非关键代码

LifecycleImpl.handleLifecycleEvent(ON_RESUME);

}

@Override

public onPause() {

//…省略非关键代码

LifecycleImpl.handleLifecycleEvent(ON_PAUSE);

}

@Override

public onDestroy() {

//…省略非关键代码

LifecycleImpl.handleLifecycleEvent(ON_DESTROY);

}

}

当然,在具体的源代码中,与上述伪代码会有一些出入,但是大体的结构是一致的。在 Jetpack 框架中,这个 Lifecycle 的实现者叫做 LifecycleRegistry。所以我们这里重点需要关注的就是 LifecycleRegistry 这个 Lifecycle 的代理接口的实现类是如何通知生命周期事件变化的。

[](()4.1 Lifecycle 接口的实现——LifecycleRegistry

[](()4.1.1 LifecycleRegistry 的订阅实现

如 2.2 节所述,通过 LiveData.observe(owner, user-defined observer),LifecycleOwner 的业务层向 LiveData 订阅数据变化,而在 LiveData.observe() 方法内,同时会自动通过 Lifecycle.addObserver(LiveData-defined observer) 向 LifecycleOwner 订阅生命周期变化:

// LiveData.observe()

@MainThread

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

//…省略非关键代码

LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

//…省略非关键代码

// 向 LifecycleOwner 发起订阅

owner.getLifecycle().addObserver(wrapper);

}

以上方法内的 owner.getLifecycle() 的实际对象即为 LifecycleRegistry,我们来看一下 LifecycleRegistry.addObserver() 的基本订阅流程:

lifecycleregistry_addobserver.png

从整个流程来看,总体可以分为三步:

  • 第一步是初始化观察者对象的状态,并将观察者缓存入队;

  • 第二步是以模拟派发生命周期事件的形式,将新加入的观察者的状态提升到目前为止可提升的最大状态;

  • 第三步是同步所有观察者的状态到全局状态。

我们可以看到,最后所有的观察者的状态都要同步到全局状态,全局状态即为 LifecyclerOwner 最新的状态。那么为什么需要进行这么繁琐的逐步模拟派发事件来进行同步呢?直接一步到位不行么?

我们可以考虑一个生命周期感知组件 LifeLocation,其功能是用于进行定位,它订阅了 LifecycleOwner,我们假设 LifeLocation 需要在 CREATED 的时候进行一些必要的初始化,而在 STARTED 的时候开始执行定位操作。假如在 LifecycleRegistry 中的状态同步可以一步同步到全局状态,那么有可能当前的全局状态已经是 RESUMED 的了,这样 LifeLocation 既得不到初始化,也无从启用定位功能了。

所以,以上这种看似繁琐的模拟派发状态事件的步骤是完全必要的,它让用户自定义的生命周期感知组件的状态切换流程是可预测的。

[](()4.1.2 LifecycleRegistry 中的事件流

我们在 4.1.1 节中的流程图的第 6 步中提到,要根据 observer.state 来计算下一个状态事件,也就是说按照事件的流向,根据当前的状态,下一个要发生的事件是什么。我们修改一下 1.2 节的时序图如下:

lifecycleregistry_event_flow

观察到图中左边的蓝色箭头,举个例子,假如当前的状态是 CREATED,那么接下来要发生的事件应该是 ON_START。蓝色箭头指示的事件流方向是生命周期由无到生的过程,我们称为 upEvent 流;与此对应,右边的红色箭头指示的事件流方向是生命周期由生到死的过程,我们称之为 downEvent。

4.1.1 节中的流程图的第 6 步中正好需要进行 upEvent 流操作。除此以外,我们在第 7 步同步到全局状态时,还需要用到 upEvent 和 downEvent 流操作,且在 LifecycleOwner 的每一次生命周期的变化中,都需要进行上述第 7 步的状态同步操作。接下来我们就看一看,当 LifecycleOwner 生命周期变化后,发生了什么。

[](()4.1.3 处理生命周期的变化

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》开源

最后

那我们该怎么做才能做到年薪60万+呢,对于程序员来说,只有不断学习,不断提升自己的实力。我之前有篇文章提到过,感兴趣的可以看看,到底要学习哪些知识才能达到年薪60万+。

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

[外链图片转存中…(img-SeWGXlqp-1649659450491)]

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

[外链图片转存中…(img-SsrqdrMg-1649659450491)]

举报

相关推荐

0 条评论