2024年Android最全安卓现代化开发系列——从生命周期到Lifecycle(1),2024年最新android生命周期面试

结语

  • 现在随着短视频,抖音,快手的流行NDK模块开发也显得越发重要,需要这块人才的企业也越来越多,随之学习这块的人也变多了,音视频的开发,往往是比较难的,而这个比较难的技术就是NDK里面的技术。
  • 音视频/高清大图片/人工智能/直播/抖音等等这年与用户最紧密,与我们生活最相关的技术一直都在寻找最终的技术落地平台,以前是windows系统,而现在则是移动系统了,移动系统中又是以Android占比绝大部分为前提,所以AndroidNDK技术已经是我们必备技能了。
  • 要学习好NDK,其中的关于C/C++,jni,Linux基础都是需要学习的,除此之外,音视频的编解码技术,流媒体协议,ffmpeg这些都是音视频开发必备技能,而且
  • OpenCV/OpenGl/这些又是图像处理必备知识,下面这些我都是当年自己搜集的资料和做的一些图,因为当年我就感觉视频这块会是一个大的趋势。所以提前做了一些准备。现在拿出来分享给大家。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

此处不必死记硬背,只需要配合状态与事件图理解其意义即可。

看完了Event,我们把视角转向State

State的代码非常简单甚至不用一丝的省略,除了枚举值外仅有一个方法:isAtLeast(state:State) ,此方法的含义是用于判断当前的状态是否大于或等于目标值的状态。

如何理解呢?还记得上文提到的吗,状态是有大小的:

我们把状态从Initialized到Resumed当做一个从小到大的状态,如果状态值变小了,则称为状态下降,反之则为状态提升

因此对于生命周期的状态而言,Created是比Initialized的,isAtLeast(state:State)的含义就是判断生命周期是否比某个预期值“走的更远”了,如果一个行为可以在组件创建后被执行,那么换句话说,只要生命周期的状态大于或者等于Created即可。

上文中提到,原生的生命周期回调无法实时获取生命周期所处的状态,一旦在生命周期回调方法中执行一些耗时操作,就无法耗时操作结束后,仍处于安全的生命周期区间,例如下面的代码:

我们尝试在onStart()中执行一段耗时操作再开启监听,但是执行耗时操作期间无法Activity是否已经处于onStop()了,此刻我们就可以使用isAtLeast(state:State)来判断耗时操作结束后的生命周期状态:

可见,「Lifecycle」库确实解决了生命周期只有事件没有状态的问题,开发者可以轻易获取当前的生命周期所处的阶段。

2.2.2、LifecycleOwner(opens new window)

首先,我们看看它的源码:

非常的简单,只是给实现者对外提供一个获取Lifecycle的入口,为什么要这样设计呢?还记得Lifecycle吗,它并不是一个接口而是一个抽象类,在Jvm中是单继承的,因此不太可能会让带有生命周期的组件直接继承Lifecycle抽象类。

因此在实际使用中,带有生命周期的组件和Lifecycle是包含的关系,即下图的情况:

为什么谷歌的开发人员要如此奇怪呢,让Lifecycle变成接口,让Activity实现接口不一样能让组件访问到Lifecycle吗?先别急,Lifecycle的具体实现我们还没看,等到那一节将会解答这个疑问。

总结:LifecycleOwner只是一个简单的对外提供访问Lifecycle的接口。

2.2.3、LifecycleObserver(opens new window)

此处就不放代码了,因为这是一个空接口,作用是将其实现者变成一个生命周期的观察者

其本身不起作用,业务中我们通常使用其子接口,例如DefaultLifecycleObserverLifecycleEventObserver等,可以回去查看2.1节的MyListener实现了DefaultLifecycleObserver之后是如何感知Activity的生命周期的。

2.2.4、LifecycleRegistry(opens new window)

此类是「Lifecycle」库的核心类,也是Lifecycle抽象类的直接实现,它的作用是管理生命周期事件的派发,但是其做了非常多的优化,例如解决了产生事件时,迭代观察者过程中可能会新增或者移除观察者,用ArrayList遍历会崩的问题、新加入的观察者如何派发事件的问题,移除观察者如何更新状态的问题等等。

这些谷歌的开发人员都帮我们解决了,只需要按下图简单配置一下即可使用:

可见,我们只需要按照上文提到的结构,在Activity中实例化一个LifecycleRegistry,然后在合适的生命周期回调中派发响应的事件,所有监听当前Activity生命周期的组件就可以获取到当前Activity的生命周期了。

**需要注意的是:**上述代码仅仅是为了为你展示Lifecycle是如何实现生命周期事件派发的,实际使用中,并不需要为Activity手动派发事件,ComponentActivityAppcompatActivity实际上已经配置好了派发逻辑,开发中直接获取Lifecycle即可。

下面即将深入LifecycleRegistry的源码层面探究一下它的原理,但是需要注意的是,本文章的目的并不是让读者100%搞懂源码中每一行代码的运行逻辑,因为这违背了本系列文章的初衷——让读者能够在对库有足够充足的了解下开发,同时笔者也没有100%搞懂源码每一行的逻辑。

下面我们看看LifecycleRegistry的代码脉络:

笔者省去了绝大部分和业务无关的代码,只保留了最核心最精华的代码,其实被移除掉的代码都是为了解决前文中提到的“遍历过程中增删列表”、”新加入的观察者如何派发事件“等细枝末节的问题,与本文主题关系不大。

可以看到,LifecycleRegistry本质上就是一个强化版的观察者模式的设计,添加观察者(observer)、遍历派发事件的模式。

还记得上文提到的一个小问题吗,为什么LifecycleOwner不直接设计成接口而是以成员变量的方式挂载在对应的生命周期组件里面呢?通过LifecycleRegistry的源码我们可以看到,LifecycleOwner被以弱引用的方式存放着的,也就是说处理生命周期事件派发的LifecycleRegistry并不会直接引用LifecycleOwner,可以认为是谷歌的开发人员是为了防止产生内存泄漏而故意设计的。

2.2.5、小总结

我们已经依次浏览了「Lifecycle」库中的四个最核心的组件,他们的关系如果你已经搞混了,笔者再次通过一段极简的代码的方式来强化读者对他们的理解:

关于四个核心组件的总结:

  1. Lifecycle描述的是存放和管理生命周期的容器
  2. LifecycleRegistryLifecycle的实现类
  3. LifecycleObserver是观察生命周期变化的监听器
  4. LifecycleOwner是对外提供Lifecycle的提供者。

3、谷歌眼中的Lifecycle

3.1、ComponentActivity

此类是谷歌官方基于Activity开发的子类,其集成了许多Jetpack库的核心功能,其中就包括了「Lifecycle」库,该类因此也实现了LifecycleOwner接口,开发者常用的AppcompatActvity也是该类的子类。

但是细读源码会发现,该类并没有像笔者之前展示的源码那样,直接调用LifecycleRegistry在特定的Activity生命周期回调中派发事件,那么该类是如何实现生命周期事件的派发的呢?下面介绍「Lifecycle」库中的另外一个关键类:ReportFragment

3.1.1、ReportFragment与LifecycleCallbacks

ComponentActivity的onCreate()中,有一段ReportFragment.injectIfNeededIn(this)的代码,这个就是实现了生命周期事件派发的核心类。

接下来让我们走进ReportFragment的源码,正如前文所述,文章并不会阐述每一行代码的原理,而是抓住主要的脉络,隐藏了和主脉络无关的代码,但是剩余的代码量仍然挺多,读者不必对大量的代码感到恐慌,因为文章会逐一解释:

可见,ReportFragment做的事非常简单,就是在其生命周期的各个阶段上报生命周期事件,因为Fragment的生命周期和Activity在绝大部分是保持一致的(特殊的如onCreate()除外,不过也有onActivityCreated()onActivityPostCreated()等可以感知Activity生命周期的函数),谷歌的开发人员于是就利用ReportFragment作为监听Activity生命周期的工具,你可以看到这个Fragment是没有UI的,这也间接证明了它的任务并不是展示一个UI而仅仅是为了监听生命周期。

让我们回到injectIfNeedIn() ,可以清楚的看到这里做了一个版本判断,如果大于api版本大于29,则使用LifecycleCallbacks做一个注册的逻辑,这是怎么回事呢?

在我提到ReportFragment是作为一个生命周期监听者而不是一个展示UI的模块的时候,你也许就已经隐隐约约闻到一种非常奇怪的味道。由于安卓源码设计的缺陷(只对外提供了回调方法而没有提供回调监听注册),开发者对待这一问题必须考虑向下兼容,因此他们选择了源码中已经存在的、可以监听Activity的生命周期的Fragment,但是在api 29之后,Activity原生自带了生命周期的回调监听注册,因此一旦检测到api大于或者等于29,ReportFragment的作用就形同虚设了,因为广播生命周期的事件的任务已经转移给Activity自带的生命周期回调来实现了。

你也许还会担心,现在有ReportFragmentActivity自带的生命周期回调两种方式了,会不会导致一个事件被广播两次呢?其实不用担心,广播的时候已经做了排除了,只有api小于29的情况下,ReportFragment才会生效。

3.2、Fragment

Fragment本身的生命周期和Activity没有很大的差异,依然是内置LifecycleRegistry然后在合适的生命周期回调中广播生命周期事件的一套,但是值得注意的是:

FragmentFragmentManager管理时,例如执行replace()事务中,逻辑上当前的Fragment只是被另外一个同类所替换了,它并没有真的被销毁(因为待会还有重新回来的机会),因此该Fragment并不会执行onDestroy(),然而由于内存上的考量,不可见的FragmentView理应被回收,因此View会被销毁。

换句话说,Fragment不可见之后,它的状态会保存起来,但是其View会被销毁,待会再次可见的时候,会根据其状态再一次执行onCreateView()

上述机制导致了一个问题:Fragment的生命周期和其对应的View的生命周期在实质上是不对等的,然而实际开发中感知生命周期大多数是为了与UI进行互动,这也导致了开发者单纯监听Fragment的生命周期已经不能够满足开发上的需求了。

下面这张来源于谷歌官方开发者文档的图片很好的诠释了Fragment和它的View的生命周期关系:

假如一个Fragment正在栈顶,他会处于Resumed的阶段,但是被replace之后,它会进入Created阶段,此刻View被销毁,View会进入Destroyed阶段,但是Fragment重回栈顶的时候,Fragment会从Created再次回归到Resume,而View会从Destroyed重回Resumed状态。

换句话说,在Fragment的生命周期中,它的View可能会反复的从Destroyed到Resumed之间移动(即不断地销毁与创建)

谷歌为了缓解这个问题,给FragmentView单独添加了一套生命周期,我们可以通过代码看到端倪:

可以看到,在Fragment执行performCreateView()的时候,会初始化ViewLifecycle,两者的生命周期事件是单独通知的。

  • 如果开发者想访问Fragment的生命周期,在Fragment中访问lifecycleOwner即可。
  • 如果开发者想访问FragmentView的生命周期,在Fragment中访问viewLifecycleOwner即可。
3.3、ViewTreeLifecycleOwner

在上述的代码中,能够直接访问ActivityFragment的Lifecycle的只能是它们的类中,而很多需要访问生命周期的地方往往是一些View中,例如要在View中监听其父组件生命周期,然而View的父控件有非常多,包括了ActivityFragment甚至是Dialog乃至更多,要想获取父组件的生命周期,只能做类型判断+类型强转的工作,这样就极大的限制了View的使用范围:

为了缓解,谷歌的开发人员提出了一种叫ViewTreeLifecycleOwner的设计,其实这个东西并没有什么神秘的,让我们直接看看源码:

通篇只有两个View的扩展函数,第一个函数的意义是给对应的View绑上一个LifecycleOwner,第二个函数的意义是不断往上查找父控件,直到查出之前绑定的LifecycleOwner

这段源码的作用挺简单的,也就是说只要给某个顶层的控件提前绑好了LifecycleOwner,那么他下辖的所有子View都可以通过往上查找的方式来找到LifecycleOwner,不得不说谷歌的开发人员真的是太厉害了,在简陋的基础下做出了非常强大的功能。

那么下面的问题是:LifecycleOwner的绑定发生在哪里呢?

3.3.1、Activity中的绑定

​ Activity的直接子类ComponentActivityAppcompatActivity均自动完成了绑定的工作,我们以ComponentActivity为例看看相关的绑定代码:

可见在ComponentActivitysetContentView被执行时,会将ActivityViewLifecycleOwner绑定其所在的WindowDecorView中,我们都知道Activity下面的所有View都是DecorView的子View,因此它们都可以直接通过谷歌开发人员提供的扩展函数直接访问到最顶层的ActivityLifecycle

3.3.2、Fragment中的绑定

Activity类似,Fragment也采用了几乎一致的绑定方式,只不过是将Lifecycle绑定在了FragmentView之上:

3.3.3、Dialog中的绑定

默认的DialogActivity是不支持ViewTreeLifecycleOwner的,因此谷歌的开发人员重新继承实现了一个新的Dialog子类:ComponentDialog,其中的绑定大同小异,简单看下源码即可了解:

看来和Activity一样,把LifecycleOwner绑定在了DecorView中。

3.3.4、意义与总结

那么谷歌的开发人员费尽心思的为以上的组件绑定ViewTreeLifecycleOwner有何用意呢?意义可大了,由于消除了组件之间的差异(均是通过View往上查找父控件直到找到LifecycleOwner的模式),我们不用在乎当前的View是在哪个控件中,都是统一通过findViewTreeLifecycleOwner()来获取最顶层控件的生命周期。

例如下面的自定义View的代码,无论在上述哪个控件中都可以用:

可见,开发者只需要关注生命周期本身,不再需要担心不同组件之间的差异了。

4、结语

安卓原生的生命周期设计只能说是毛坯房都算不上的水平,然而通过「Lifecycle」库的加持之后,开发者可以轻松访问组件的生命周期,让开发业务更加的合理与安全。

作为开发者的你,应该逐渐将重写生命周期函数的方式逐渐过渡到「Lifecycle」的开发方式中来,在一些工具类亦或者其他业务类中,你也可以使用「Lifecycle」辅助强化与生命周期相关的业务。

Android 学习笔录

Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

最后

想要了解更多关于大厂面试的同学可以点赞支持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值