一、LifeCycle原理

Lifecycle的生命周期状态事件和状态

Lifecycle是一个抽象类,其内部包括了添加和移除观察者的方法,还包括了此前说到的Event和State枚举。Lifecycle使用两个枚举来跟踪其关联组件的生命周期状态,这两个枚举分别是Event和State。
State指的是Lifecycle的生命周期所处的状态。
Event代表Lifecycle生命周期对应的事件,这些事件会映射到Activity和Fragment中的回调事件中。

Lifecycle如何观察Activity和Fragment的生命周期

Activity和Fragment已经默认实现了LifecycleOwner接口,LifecycleOwner可以理解为被观察者

ComponentActivity内创建了LifecycleRegistry,LifecycleRegistry是Lifecycle的实现类,并注入到了ReportFragment。ReportFragment中会调用dispatch方法,对生命周期event事件进行分发。

到了LifecycleRegistry.handleLifecycleEvent进行处理。

ComponentActivity中-->onCreate-->ReportFragment.injectIfNeededIn(this);-->dispatchCreate/dispatchStart/dispatchResume-->dispatch-->LifecycleRegistry.handleLifecycleEvent-->moveToState-->sync-->backwardPass/forwardPass-->observer.dispatchEvent-->mLifecycleObserver.onStateChanged

在activity中,getLifecycle().addObserver(LifecycleObserver)将观察者和被观察者联系在一起
Lifecycle的实现类LifecycleRegistry中handleLifecycleEvent处理页面生命周期的走向,通过event的事件,驱动state状态的改变observer.dispatchEvent(lifecycleOwner, event);-->mLifecycleObserver.onStateChanged(owner, event);

onStateChanged-->ReflectiveGenericLifecycleObserver-->invokeCallbacks-->ClassesInfoCache(反射优化)
在createInfo中获取方法上的注解OnLifecycleEvent通过反射调用invokeCallback

Android Jetpack架构组件(三)带你了解Lifecycle(原理篇) | BATcoder - 刘望舒
实现LifecycleObserver接口的类中,注解修饰的方法和事件会被保存起来,通过反射对事件的对应方法进行调用。或者使用注解处理器,生成的Java代码里就是接口的回调。

利用events事件来改变states状态:

Lifecycle包含了移除、添加观察者,还 使用两个枚举来跟踪其关联组件的生命周期状态,这两个枚举分别是Event和State。
State指的是Lifecycle的生命周期所处的状态。
Event代表Lifecycle生命周期对应的事件,这些事件会映射到Activity和Fragment中的回调事件中。

Android Jetpack架构组件(三)带你了解Lifecycle(原理篇) | BATcoder - 刘望舒

​​​​​​Lifecycle 使用与源码分析——彻底搞懂Lifecycle原理_薛瑄的博客-CSDN博客_lifecycle原理

生命周期事件管理利器 —— Lifecycle 原理详解 - 简书

二、ViewModel原理

ViewModel管理的数据有一个特点,就是不会随着页面配置改变而销毁,但在页面销毁时则会正常跟着销毁。整体流程比较清楚:​​​​​​Android ViewModel 实现原理 - 知乎

ViewModel原理 - 掘金

ViewModel 使用及原理解析 - 掘金

1、viewmodel的获取:首先调用ViewModelProvider.get()方法,从ViewModelStore中获取ViewModel,有则直接返回,没有就创建后返回。

ComponentActivity持有一个ViewModelStore,可以通过ViewModelStoreOwner中的getViewModelStore()方法获取。

HashMap<String, ViewModel> mMap = new HashMap<>();

mMap 是ViewModelStore 中有且仅有的成员变量,看它的泛型类型参数就能明白,它就是 ViewModelStore 用来存储 ViewModel 的池子。

final void put(String key, ViewModel viewModel)

ViewModelStore 顾名思义,它是负责储存 ViewModel 的一个类。引用 ViewModelStore 代码注释中的一段话表示它的功能:

ViewModelStore 的实例必须在发生配置更改时得以保留:如果此 ViewModelStore 的所有者由于配置的改变而被销毁并重新创建,那么所有者的新实例应该具有相同的 ViewModelStore 旧实例。

2、viewmodel中值的保存和恢复:

1,系统配置改变时,构建一个NonConfigurationInstance,将ViewModelStore保持到NonConfigurationInstance,再将NonConfigurationInstance保存到ActivityClientRecord的lastNonConfigurationInstances

2,恢复时,将ActivityClientrecord的lastNonConfigurationInstances传递给新的Activity,再通过getViewModelStore()获取时就能从新的Activity的lastNonConfigurationInstances获取ViewModelStore,进而获取之前的ViewModel

Android Jetpack(二)ViewModel 组件原理剖析_Chiclaim-CSDN博客

ViewModel 的基本原理就是

Q1:viewModel什么时候保存值?

在 configuration changes 的时候,在界面 destroy 的时候(ActivityThread.performDestroyActivity)通过 onRetainNonConfigurationInstance 方法将 NonConfigurationInstances 对象(里面包含 ViewModel) 保存起来。

Q2:viewModel什么时候恢复?

在重建 Activity 的时候在 attach 方法中(ActivityThread.performLaunchActivity)将上次保存的 NonConfigurationInstances 对象赋值给 Activity 的成员变量 mLastNonConfigurationInstances,然后在 onCreate 中通过 getLastNonConfigurationInstance 方法获取上次保存的 NonConfigurationInstances 对象。

ViewModel.onCleared() 资源回收:

既然ViewModel是生命周期感知的,那么何时应该清理ViewModel呢?

我们来到FragmentActivity的onDestroy()方法,发现它是在这里清理的.

/*** Destroy all fragments.*/
@Override
protected void onDestroy() {super.onDestroy();if (mViewModelStore != null && !isChangingConfigurations()) {mViewModelStore.clear();}mFragments.dispatchDestroy();
}

三、LiveData原理

Jetpack LiveData 是时候了解一下了 - 掘金

LiveData是一个数据持有组件,主要用来通知数据观察者数据发生了更新,它通过与LifecycleOwner组件绑定,实现可以只在页面活跃状态下发起通知,并在页面销毁时自动取消订阅,防止内存泄漏。

Jetpack LiveData 是时候了解一下了 - 掘金

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

相关问题:

Q1:LiveData是如何观察生命周期变化的?

简单回答:LifecycleBoundObserver添加到Lifecycle中完成注册,通过LifeCycle监听生命周期变化

详解如下:

如何观察生命周期,我们需要通过他的observe方法去看,我们上源码:

#LiveData.javapublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {//该方法调用者必须在主线程assertMainThread("observe");//如果处在DESTROYED 状态,则没必要添加观察者if (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignorereturn;}//包装观察者LiveData.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer);//将包装结果添加到Map里LiveData.ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);...//监听生命周期owner.getLifecycle().addObserver(wrapper);}

我在源码加了几个注释,我们一个个看。

注释一:可以看出通过当前组件的LifecycleOwner拿到生命周期的状态,如果是DESTORY就返回,不做任何处理。

注释二:新建了一个LifecycleBoundObserver包装类,添加大盘Map里

注释五:将LifecycleBoundObserver添加到Lifecycle中完成注册,所以我们LiveData的生命周期观察其实来源于LifecycleOwner,这也就是为什么LiveData具备了观察组件生命周期变化的能力。

Q2:observe是如何根据生命周期变化进行同步数据的?

LifecycleBoundObserver实现了onStateChanged方法,根据观察到的生命周期:STATE是DESTROYED时会移除观察者监听;STARTED和RESUMED为活跃状态则进行事件分发dispatchingvalue调用considerNotify,再次检查是否还是活跃的,不活跃不通知,后面就是活跃的则onChanged通知

那么我们的LiveData什么时候会通知观察者呢?不用想,肯定是数据更新的时候,而数据的更新是我们代码自己控制的,通过post/setValue进行通知观察者更新数据。整体流程:

setvalue --> dispatchingValue(遍历所有观察者找到对应的LifecycleBoundObserver) --> 通知considerNotify() --> 检查是否还是活跃的,否则不通知,后面就是onChanged通知

Q3:通知观察者

1、宿主的生命周期发生变化:当宿主(Activity/Fragment) 生命周期发生改变时会调用onStateChanged()。
2、通过调用setValue()/postValue() 触发。

Q4:postValue和setValue的区别是什么?

我们知道虽然我们调用observe方法对数据进行观察,但是真正同步数据的代码是postValue和setValue。postValue其实是在子线程操作,最后通过postToMainThread同步至主线程,最后其实还是调用了setValue方法。

Q5:优点:

a、生命周期感知:

借助Lifecycle 能够感知生命周期各个阶段的状态,进而能够对不同的生命周期状态做相应的处理。

正因为可以感知生命周期,所以:

  • 可以在活跃状态时再更新UI 。
  • UI 保持最新数据(从非活跃到活跃状态总能收到最新数据)。
  • 观察者无需手动移除,不会有内存泄漏。
  • Activity/Fragment 不存活不会更新UI,避免了Crash。
  • 粘性事件设计方式,新的观察者无需再次主动获取最新数据。

还有个额外的特点:稍微改造一下,LiveData 可以当做组件之间消息传递使用。

b、数据实时同步

在主线程调用时:LiveData.setValue(xx)能够直接将数据通知到观察者。
在子线程调用时:LiveData.postValue(xx)将数据暂存,并且切换到主线程调用setValue(xx),将暂存数据发出去。
因此,从数据变更--->发送通知--->观察者接收数据 这几个步骤没有明显地耗时,UI 能够实时监听到数据的变化。

Q6:缺点:

a、postValue(xx) 数据丢失

postValue(xx)每次调用时将数据存储在mPendingData 变量里,因此后面的数据会覆盖前面的数据。LiveData 确保UI 能够拿到最新的数据,而此过程中的数据变化过程可能会丢失。
问题的原因是:不是每一次数据变更都会post到主线程执行。

b、粘性事件

相信大家看到过一些博客的分析也知道了LiveData 粘性事件问题。
粘性事件:

数据变更发生后,才注册的观察者,此时观察者还能收到变更通知。

明明是全新注册的观察者,而且此时没有新的数据变更,却依然收到之前的数据。
这和LiveData 的实现有关,看看核心源码实现:

#LiveData.javaprivate void considerNotify(LiveData.ObserverWrapper observer) {//mVersion 为LiveData 当前数据版本,当setValue/postValue 发生时,mVersion++//通过比对LiveData 当前数据版本与观察者的数据版本,若是发现LiveData 当前数据版本 更大//说明是之前没有通知过观察者,因此需要通知,反之则不通知。if (observer.mLastVersion >= mVersion) {return;}//将观察者数据版本保持与LiveData 版本一致,表明该观察者消费了最新的数据。observer.mLastVersion = mVersion;observer.mObserver.onChanged((T) mData);}

再回溯一下流程:

1、初始时LiveData.mVersion= -1,ObserverWrapper.mLastVersion = -1,因此初次进入Activity时没有数据通知。
2、当点击按钮后(LiveData.setValue()),此时LiveData.mVersion = 0;因为LiveData.mVersion>ObserverWrapper.mLastVersion,因此观察者能够收到通知。
3、当退出Activity 再进来后,因为ObserverWrapper 是全新new 出来的,ObserverWrapper.mLastVersion = -1,而LiveData.mVersion =0,还是大于 ObserverWrapper.mLastVersion,因此依然能够收到通知。

要解决这个问题,很直观的想法是从version字段出发,而LiveData、ObserverWrapper 并没有对外暴露方法来修改version,此时我们想到了反射。

通过反射修改ObserverWrapper.mLastVersion 的值,使得在第一次注册时候保持与LiveData.mVersion 值一致。

Q7:LiveData的坑

Jetpack LiveData 是时候了解一下了 - 掘金

面试:LiveData的坑数据丢失问题_王温暖的博客-CSDN博客

四、DataBinding原理

Android中的DataBinding的原理浅析 - 简书

面试:Jetpack相关相关推荐

  1. Python面试-DB相关

    昨日回顾: 面试 Python综述 设计哲学 版本变迁及发展 GIL 内存管理及垃圾回收 并发并行 昨日作业一:Python是否存在内存泄露 作业二:过往的项目中有没有出现过性能问题? 作业三:什么是 ...

  2. [前端面试]HTTP相关常问问题

    [前端面试]HTTP常问问题 HTTP(HyperText Transfer Protocol)是一种用于在网络上传输超文本的协议.面试中,可能会有以下常见的问题: HTTP 的工作原理 HTTP 的 ...

  3. python中db是什么意思_Python面试-DB相关

    昨日回顾: 面试 Python综述 设计哲学 版本变迁及发展 GIL 内存管理及垃圾回收 并发并行 昨日作业一:Python是否存在内存泄露 作业二:过往的项目中有没有出现过性能问题? 作业三:什么是 ...

  4. 【面试福利篇】英文面试的相关资料

    要求做英文面试的单位越来越多了.应聘外企,自然主要是英文面试:应聘国内的企业,面试进行到一半的时候,好多也会突然冒出些英文面试来.因此,对于英文面试,我们不能等闲待之.下面是一些英文面试的对话实例. ...

  5. 关于Jetsonnano底层板和TF拓展卡jetpack相关版本的相关错误问题。【解决某些系统进入失败问题】

    前提: 本人使用的板子是创乐博提供的Jetson nano 4G版本(B01),根据创乐博提供的教程刷入系统后因为nano自身架构问题pip安装所需torch.cuda.torchvision等出现问 ...

  6. 测试面试问道MySQL,面试---mysql相关

    前言:在2019年的年末,我又再一次的踏上了面试的漫漫征途.每次的面试准备都是对自己学习的一次积累.目前已经尘埃落定,将自己面试准备的东西做一次整理. 面试准备时长:1.5个月 mysql基本上每次面 ...

  7. 51sap SD模块面试问题相关热门问题总结

    SD面试中的问题: 在开发票时系统一般会报哪些错误,应该如何解决? 答: A.交货单类型不能出具发票类型.处理:检查系统后台配置发票复制控制中有没有该交货单类型与出具发票类型设定复制规则. B.交货单 ...

  8. 【运维面试】关于运维面试ELK相关的问题核心梳理(必看)

    文章目录 1. 各个组件的作用 2. 应用场景: 3. elasticsearch 存储结构 4. RESTful API 增删改查 a) 创建索引: b) 查询所有 c) 查看map d) 删除索引 ...

  9. 安卓 sharedpreferences可以被其它activity读取_Google|再见 SharedPreferences 拥抱 Jetpack DataStore...

    Google 新增加了一个新 Jetpack 的成员 DataStore,主要用来替换 SharedPreferences, DataStore 应该是开发者期待已久的库,DataStore 是基于 ...

最新文章

  1. Python数据分析学习文章归纳
  2. 运维自动化之Cobbler安装配置
  3. 关系型数据库和mysql教材_关系型数据库(MySQL)
  4. ASP.NET MVC3 301永久重定向实现程序
  5. C#根据字节数截取字符串
  6. 找到的比较好的工作面试题笔试题
  7. 如何用AR升级星巴克体验?阿里工程师祭出了“三板斧”
  8. JavaScript 异步执行的学习笔记 - 什么是事件循环 Event loop?
  9. WPF中删除打开过的图片
  10. Vue cli3+Hubuilder将项目打包为App
  11. Android 无法查看外部依赖jar的源码的问题
  12. 疫情之后,人工智能该如何走?
  13. [转载] Python——摄氏温度转换华氏温度
  14. 【代码优化】构造器参数繁多时候,考虑使用builder模式
  15. 运动世界校园3.0版本逆向分析破解
  16. 计算机学机械制图吗,机械制图为什么这么难学?
  17. 12306GT多线程、分流免费抢票工具使用
  18. 测试英语词水平的软件,英语词汇量测试程序
  19. 如何把计算机组成原理、操作系统、数据结构和计算机网络融会贯通,相互联系起来?
  20. Oracle 递归查询详解

热门文章

  1. java.lang.NoClassDefFoundError: org/openjdk/jol/info/ClassLayout
  2. 灵活替换、无惧缺芯,ARM工控板中的模块化设计
  3. Linux ARM 静态网络配置
  4. 20210630个人复盘
  5. 简单温习一下快速排序
  6. 从抄书到开源之巅:章亦春的程序人生(转载自微信公众号 -- 码农翻身)
  7. 频域特征提取的Python实现(频谱、功率谱、倒频谱)
  8. could not locate named parameter 的解决方法
  9. The Thirty-fifth Of Word-Day
  10. 何时是PNE(纯策略纳什均衡)?何时是MNE(混合策略纳什均衡)?