LifeCycle基础(一)
-
LifeCycle的职责
-
可以检测Activity或者Fragment的生命周期函数
-
依托观察者设计模式实现
- Activity/Fragment:Observable(被观察者)
- LifeCycle:Observer(观察者)
-
图示:
-
-
不使用LifeCycle,去监听Activity/Fragment的生命周期(使用监听器)
-
工程结构
-
思路:
-
创建一个监听器类,编写函数(监听器的动作)
package com.derry.lifecycle.user1 import android.util.Log class MyListener { private val TAG = "MyListener" fun start() = Log.d(TAG, "start run ...") fun stop() = Log.d(TAG, "stop run ...") }
-
在MainActivity处,实例化监听器,重写生命周期函数,在其中调用监听器方法
package com.derry.lifecycle.user1 import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.derry.lifecycle.R // TODO 第一个版本 监听器监听生命周期 class MainActivity : AppCompatActivity() { private var myListener: MyListener ? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myListener = MyListener() } override fun onStart() { super.onStart() myListener ?.start() // 会出现人为失误,一旦出现人为失误 造成不一致性功能问题 } override fun onStop() { super.onStop() myListener ?.stop() // 会出现人为失误 } }
-
-
运行结果
-
启动APP时:
-
退出APP时(按返回键退出):
-
-
实现细节:
-
需要在MainActivity(被监听处)中的onCreate方法中声明实例化监听器
- 实际上就是实现类间通信,在类A中调用类B的方法而已
-
推荐将监听器写成全局变量
-
注意Kotlin的?使用:就是在声明以及调用的时候要用到
-
-
-
第二版(模仿MVP架构,P层监听生命周期)
-
为什么P层需要去监听生命周期函数
-
场景:
当P层数据需要回馈给Activity,此时当Activity消亡后,再回馈就会出问题;因此需要在P层监听
-
-
工程结构
-
思路:
-
创建MyPresenter.kt:在这个里面编写函数(当监听到不同生命周期时,执行相应的动作)
package com.derry.lifecycle.user2 import android.util.Log class MyPresenter { private val TAG = "MyPresenter" fun onResume() = Log.d(TAG, "onResume run ...") fun onPause() = Log.d(TAG, "onPause run ...") }
-
创建MainActivity.kt
- 在MainActivity处,实例化监听器,重写生命周期函数(在其中调用监听器方法)
package com.derry.lifecycle.user2 import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.derry.lifecycle.R // TODO 第二个版本 MVP 的 P层 class MainActivity : AppCompatActivity() { private var myPresenter: MyPresenter ? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myPresenter = MyPresenter() } override fun onResume() { super.onResume() myPresenter ?.onResume() // 会出现人为失误,这个万一写掉了相应的功能就完犊子了(加入有100个Activity)会造成不一致性 } override fun onPause() { super.onPause() myPresenter ?.onPause() // 会出现人为失误 } }
-
-
运行结果:
-
分析总结:
- 这个看起来跟使用监听器进行生命周期函数监听差不多,这个实际上是去模仿了一下业务场景;就是去引出LifeCycle这个东西
-
-
第三版(基础版)
-
继承关系:会实现LifecycleOwner(这个在AndroidX中会实现这个借口)
-
将光标放在MainActivity上,CTRL+H
-
-
结构:
-
创建MainActivity(实现观察者与被观察者的关联)
package com.derry.lifecycle.user3 import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.derry.lifecycle.R // TODO 第二个版本 MVP 的 P层 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 一般是在BaseActivity 关联注册的 // 观察者 与 被观察者 关联的环节 lifecycle.addObserver(MyObserver())//在kotlin中会将get 省略掉 } }
-
创建观察者类MyObserver(眼睛):实现观察者接口+使用注解来监听生命周期
package com.derry.lifecycle.user3 import android.util.Log import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent // 观察者 眼睛 class MyObserver : LifecycleObserver { private val TAG = "MyObserver" @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) // 画面可见 就连接 fun connectListener() = Log.d(TAG,"connectListener run ...") @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) // 画面不可见 就断开连接,通过注解来监听生命周期 fun disconnectListener() = Log.d(TAG,"disconnectListener run ...") }
-
运行截图:查看日志文件
-
-
第三版(plus)
-
基础版本的缺点:
- 使用注解才能监听生命周期
- 不能拿到环境(Activity,Fragment所有环境),拿到了就可以Toast,增加弹窗了
-
解决办法:让观察者实现DefaultLifecycleObserver接口
-
接口继承关系:
- DefaultLifecycleObserver->FullLifecycleObserver->LifecycleObserver
-
观察者2(第二双眼睛)MyObserver2
package com.derry.lifecycle.user3 import android.util.Log import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner // DefaultLifecycleObserver 就是对 LifecycleObserver 二次封装 为了用户好用 class MyObserver2 : DefaultLifecycleObserver { private val TAG = "MyObserver2" override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) Log.d(TAG,"onCreate run ..." } override fun onResume(owner: LifecycleOwner) { super.onResume(owner) Log.d(TAG,"onResume run ...") } override fun onPause(owner: LifecycleOwner) { super.onPause(owner) Log.d(TAG,"onPause run ...") } }
在MainActivity中注册: lifecycle.addObserver(MyObserver2())
-
工程规范,一般情况下是在BaseActivity中进行观察注册的
-
应用场景:
-
使用LifeCycle观察这个Activity,Fragment的变化并做逻辑处理
-
例如:当画面可见的时候才弹窗
- 微信中:当手机熄屏的时候,会收到消息,但只有在当页面可见的时候,这一瞬间才更新UI
-
画面不可见的时候,不干活:这个时候使用LifeCycle可能会造成内存泄漏
-
-
-
第四版:内部类实现接口去监听(总是感觉怪怪的)
-
好处
- 不用定义额外的类
- 不用额外重写方法
- 分层结构化,看起来更加清晰
-
MainActivity
package com.derry.lifecycle.user4 import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import com.derry.lifecycle.R // TODO 第四个版本 会内部类 监听 class MainActivity : AppCompatActivity() { private val TAG = "MainActivity" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 一般是在BaseActivity 关联注册的 lifecycle.addObserver(MyObserver()) } inner class MyObserver : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun onResume() { Log.d(TAG, "Lifecycle call onResume"); // 逻辑 } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun onPause() { Log.d(TAG, "Lifecycle call onPause"); } } /*override fun onResume() { super.onResume() // 逻辑 }*/ }
-
-
第五个版本:接口监听法(使用较多的)
-
在工程中多用这个
-
工程结构:
-
IPresenter
package com.derry.lifecycle.user5 import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent interface IPresenter : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun onResume() @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun onPause() }
-
MainActivity
package com.derry.lifecycle.user5 import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import com.derry.lifecycle.R // TODO 第五个版本 接口监听法,设计模式的设计环节,你会见到这种写法 class MainActivity : AppCompatActivity() { private val TAG = "MainActivity" private var myPresenter : IPresenter ? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 一般是在BaseActivity 关联注册的 (省略:工厂设计模式) myPresenter = MyPresenter3()//使用工厂设计模式就可以改变观察的对象 //关联一下 lifecycle.addObserver(myPresenter !!) } }
-
MyPresenter
package com.derry.lifecycle.user5 import android.util.Log class MyPresenter : IPresenter { private val TAG = "test" override fun onResume() { Log.d(TAG, "Lifecycle call onResume") } override fun onPause() { Log.d(TAG, "Lifecycle call onPause") } }
-
MyPresenter2
package com.derry.lifecycle.user5 import android.util.Log class MyPresenter2 : IPresenter { private val TAG = "test" override fun onResume() { Log.d(TAG, "Lifecycle call onResume") } override fun onPause() { Log.d(TAG, "Lifecycle call onPause") } }
-
MyPresenter3
package com.derry.lifecycle.user5 import android.util.Log class MyPresenter3 : IPresenter { private val TAG = "test" override fun onResume() { Log.d(TAG, "Lifecycle call onResume") } override fun onPause() { Log.d(TAG, "Lifecycle call onPause") } }
-
源码分析
-
工程结构:
-
代码展示:这里模拟了一个地图APP,通过生命周期函数来分析Lifecycle源码
MainActivity
package com.derry.lifecycle.source1 import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.derry.lifecycle.R // TODO 被观察者 // 源码分析 // 不在Activity里面写 是为了降低耦合吗 ? // Google考虑的是,你继承AppCompatActivity 可以,你继承 XXXXActivity 也可以 class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 观察者 == MyLocationListener // 1.主线流程,支线流程不管(防止淹死源码) // 2.支线流程 lifecycle.addObserver(MyLocationListener())//在kotlin中是不用new的 } override fun onResume() { super.onResume() // CREATE ---> START ---> RESUME } override fun onStop() { super.onStop() // initial -> create 要执行onCreate /*addObsever()的时候是初始状态 后面只执行了onDestroyed() 所以是onCreate和onDestroyed*/ // lifecycle.addObserver(MyLocationListener()) } }
MyLocationListener
package com.derry.lifecycle.source1 import android.util.Log import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent // 地图定位功能的模拟 眼睛 Observer 观察者,眼睛去看什么就在这个里面去看,在MainActivity中去关联被观察者 class MyLocationListener : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun create() = Log.d("Derry", "create 正在启动系统定位服务中...") @OnLifecycleEvent(Lifecycle.Event.ON_START) fun start() = Log.d("Derry", "start 连接系统定位服务...") @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun resume() = Log.d("Derry", "resume 系统定位的界面展示...") @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun pause() = Log.d("Derry", "pause 系统定位的界面关闭...") @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun stop() = Log.d("Derry", "stop 断开系统定位服务...") @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun destroy() = Log.d("Derry", "destroy 正在停止系统定位服务...") }
-
分析方法:
- 始终抓住主线流程(决定走向的地方)
-
分析实例:自己创建的观察者MyLocationListener在系统中是如何调用的
-
步骤:点击红色箭头查看源码(CTRL+鼠标左键)
- 跳转到MainActivity中(添加眼睛:将观察者与被观察者进行关联)
- 点击这个接口按钮进行跳转
- 可以看到眼睛作为ObserverWithState类的构造参数,再次跳转(查看ObserverWithState具体的构造函数),点击红色箭头
- 在ObserverWithState类的构造方法中,可以看到眼睛observer,作为函数实参传入了这个Lifecycling.lifecycleEventObserver()中,继续点击进行跳转
- 在Lifecycling.lifecycleEventObserver()中,可以看到它将参入的参数弄成了一个object
- 滑动鼠标滚轮,在这个LifecycleEventObserver的最后一行,发现这个object作为构造参数,进行了ReflectiveGenericLifecycleObserver类的实例化,点击,继续跳转
- 下图中,可以看到ReflectiveGenericLifecycleObserver的构造方法中,先对传入的参数做了暂存,放在了mWrapped中,然后使用了参数的字节码文件(引入反射),继续点击红色箭头
- 此时,跳转到了CallbackInfo类中,下滑鼠标,找到private CallbackInfo createInfo(Class<?> klass, @Nullable Method[] declaredMethods) {}这个函数;
- 下图中的红色框中,发现在这个我们将创建的MyLocationListener,通过反射获取到其字节码文件并将其放到了Map里面去:方便后续宿主(Activity或者Fragment的生命周期)通过反射进行激活
-
-
源码分析经验:使用Map提升性能(时间换空间)
CallbackInfo getInfo(Class<?> klass) { //当第一次拿到这个观察者的话,就将他塞到这个Map里面去。下一次再碰到这个(相同的观察者)就直接从Map里面去拿,大多数系统源码都会这样去搞一个Map缓存: //反射往往搭配Map进行使用 //第一次创建,第二次从缓存里面去拿, CallbackInfo existing = mCallbackMap.get(klass); if (existing != null) { return existing; } existing = createInfo(klass, null); return existing; }
-
观察者会被放到Map里面,ReflectiveGenericLifecycleObserver--->ClassesInfoCache这个类里面
//使用cache保存了观察者的类注解等信息全部放到Map里面去。方便宿主通过反射进行激活 CallbackInfo info = new CallbackInfo(handlerToEvent); mCallbackMap.put(klass, info); mHasLifecycleMethods.put(klass, hasLifecycleMethods);
-
状态与事件(这个就是一个难点了)
-
当宿主发生生命周期后,怎么在LifeCycle中进行感知?(引入状态机)
-
先解决这个怎么关联的问题
- 进入MainActivity的父类:AppCompatActivity
- 进入AppCompatActivity的父类:FragmentActivity
- 再进入FragmentActivity的父类:ComponentActivity
- 在这个ComponentActivity里面,实现了一个接口,点进去
- 发现:有这个getLifecycle();这个,就相当于在MainActivity中的关联lifecycle.addObserver(MyLocationListener())
-
-
开始处理感知问题:返回上一步(ComponentActivity类),去找他的onCreate方法,这里会创建一个空白(无UI)的Fragment
-
在Gradle源码中,常常使用一个空白(无UI的Fragment)黏贴到你想要监听的地方,宿主去执行onStart,这个空白的Fragment(ReportFragment)也会执行onStart,
-
在这个ReportFragment.java中下滑鼠标,这个是有对应的六个生命周期函数的,牵涉到了事件的分发(这里面会做版本控制,低于29直接开始分发事件;高于29会使用切面的方式,切出去,但是最后还是会回来,上图;)
- 就是这个接口了
-
-
现在开始最难的地方了:处理事件分发
- 拿到事件,扔到getStateAfter里面去:这里是根据event事件拿到状态next,再根据状态去对齐
- 使用switch-case:对应不同的事件,返回不同的状态
- 事件取值代码展示
- 状态取值代码展示
-
事件驱动状态:这个就是状态机
- ON_RESUME没有倒退状态
- mState:会记录所有的状态
- mActive:bool值,当状态为STAERED或者RESUMED,这个变量为true,其他的状态都是false,这个变量会在LiveData中作为权限标识,只有在true的时候才会去干活
- 状态机如图(通过事件来决定状态转移的过程):从左至右枚举值逐次递增
-
状态对齐:保证观察者与被观察者状态相同(被观察者往往要走的快一点,比如被观察者在STARTED,观察者还在CREATED)
- 当状态对齐完成(这个是怎么对齐的?代码在哪里呢),就退出同步操作
- 当状态不同时,通过枚举类型比大小,决定是前进(forwardPass)还是后退(bankwdPass)
-
实例:以倒退流程举例:
- 查看源码,确实会执行ON_STOP事件(这里就是通过状态退出事件)

-
实例:当观察者为CREATED,被观察者是STARTED,被观察者大,就前进
此时观察者就会前进,更新状态(在比较枚举值的时候,观察者小于被观察者)
- 这个时候,需要将观察者更新,需要前进,进人upEvent函数(根据观察者的状态拿到这个函数的返回值(需要执行的一个事件))这里还有一次检测,
- 处理事件分发,当被观察者是STARTED,返回ON_RESUME作为dispatch的参数
- 这里会进行二次检测:
- 继续点击
- 继续点击
- 继续点(这个就是前面留的那个坑)
- 继续,反射执行
- 继续,反射执行
- 就到这里了,这里会通过反射进行调用MyLocationListener的ON_RESUME方法:实现了事件分发
- 会执行MyLocationListener中注解处理器对应的ON_RESUME
-
处理坑:mActive
-
LiveData能拿到LifeCycle状态,所以它才会有许多的功能特性
-
解绑解决内存泄漏,当Activity为DESTROYED,将LiveData的观察者解绑,这样就不会造成内存泄漏
-
这个LiveData可以拿到Lifecycle的状态,就可以去偷懒了
-
-
填坑:注册位置不同:在onResume中,onStop中注册
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 观察者 == MyLocationListener // 1.主线流程,支线流程不管(防止淹死源码) // 2.支线流程 lifecycle.addObserver(MyLocationListener())//在kotlin中是不用new的 } override fun onResume() { super.onResume() // CREATE ---> START ---> RESUME:在这里注册,也可以用,就会在while连续对齐两次 lifecycle.addObserver(MyLocationListener()) } override fun onStop() { super.onStop() // initial -> create 要执行onCreate /*addObsever()的时候是初始状态 后面只执行了onDestroyed() 所以是onCreate和onDestroyed*/ // lifecycle.addObserver(MyLocationListener()) } }
-
状态机相关:
-
为什么要搞状态机,直接在更新的时候赋值就行
- 状态机只能按照事件改改变状态
- 这个是为了给以后的框架使用,不是给程序猿用的
- 状态机的起点是INITIALIZED,状态只能是通过事件进行更新
- 观察者与被观察者都只能保持一个状态,通过这个状态来决定是前进还是倒退
-
-
-
知识细节
-
被观察者(Observable)--->宿主:实现了LifeCycleOwner的,用这个接口来维护
- Activity
- Fragment
-
使用的是support4不是AndroidX的话,就没有Jetpack,没有这个接口(AndroidX是默认的)
-
观察者Observer:实现了LifeCycleObserver接口,这个就是眼睛
-
使用LifeCycle.addObserver(观察者):这样就关联起来了
-
-
知识补充:
-
生命周期函数的执行时机
-
as快捷键查看继承关系:
- 将光标悬停在想要查看的类上
- CTRL+H
-
as快捷键查看类的结构
- ALT+ 7
- CTRL+F12
-
as快捷键分析源码
- 回退到上一步:CTRL+ALT+左方向键
- 前进到下一步:CTRL+ALT+右方向键(基于查看的历史)
-
怎么去制作动图:
-
如何实现枚举大小比较:
-
工厂设计模式
-
反射
-
-
异常处理
-
在导入别人的文件的时候
-
异常信息
Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Faile
-
解决办法
在这个文件里面添加如下语句后刷新,即可
android.overridePathCheck=true
-
-
在其中项目的时候,发现运行的不是自己想要的那个
-
设置AndroidManifest.xml
-
即可启动这个user1/MainActivity
-
-
启动失败
- 同步一下Gradle文件+重新启动即可
- 或者对照日志进行处理
-