简介
Lifecycle是Google官方提供的Jetpack组件库中的一个组件,它为用户构建生命周期感知型组件提供了便利,让用户开发的组件可以感知到系统组件的生命周期变化,根据系统组件的状态调整自己的行为,避免了对系统组件生命周期回调方法的依赖,从而完成了用户开发的组件和系统组件的解耦,也可以在一定程度上降低内存泄露的发生。上述的系统组件包括但不限于Activity、Fragment和LifecycleService。
Lifecycle的几种使用场景
解耦页面和组件
假设有个需求需要在页面上显示在该页面上已停留时间。可以使用系统提供的控件Chronometer,在页面onResume时开始计时,在onPause时停止计时,再加上一些时间的处理,可以用下面的代码实现
class LifecycleActivity : AppCompatActivity() {
/**
* 使用传统方式实现
*/
private lateinit var chronometer: Chronometer
private var elapsedTime: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lifecycle)
chronometer = findViewById(R.id.chronometer)
}
override fun onResume() {
super.onResume()
chronometer.base = SystemClock.elapsedRealtime() - elapsedTime
chronometer.start()
}
override fun onPause() {
super.onPause()
elapsedTime = SystemClock.elapsedRealtime() - chronometer.base
chronometer.stop()
}
}
不难看出,代码中计算时间的逻辑需要依赖Activity的生命周期回调方法,一个需求需要加这样一段,如果该页面还有其他类似功能,那可想而知,生命周期回调方法必然变得臃肿,进而导致Activity代码膨胀。还有一点,对于某些申请资源的代码,非常容易在需要释放资源的地方遗漏掉。所以,这就要求我们开发的组件最好具有生命周期感知能力,根据系统组件的生命周期状态的变化进行自管理。
下面我们把这个例子改进一下,使用Lifecycle
class MyChronometer @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : Chronometer(context, attrs, defStyleAttr), LifecycleObserver {
private var elapsedTime: Long = 0
@OnLifecycleEvent(ON_RESUME)
private fun startMeter() {
base = SystemClock.elapsedRealtime() - elapsedTime
start()
}
@OnLifecycleEvent(ON_PAUSE)
private fun stopMeter() {
elapsedTime = SystemClock.elapsedRealtime() - base
stop()
}
}
我们继承了Chronometer,并且实现LifecycleObserver接口,这个接口没有需要实现的方法,它只是把class做一个标记,表明该class是一个LifecycleObserver可以观察LifecycleOwner的生命周期变化。代码中还有两个方法值得注意,startMeter和stopMeter,它们的注解分别是@OnLifecycleEvent(ON_RESUME)和@OnLifecycleEvent(ON_PAUSE),当该控件被添加到观察者中时,一旦LifecycleOwner的生命周期方法被回调了,就会触发对应注解的方法。生命周期事件有
- ON_CREATE
- ON_START
- ON_RESUME
- ON_PAUSE
- ON_STOP
- ON_DESTROY
- ON_ANY 根据自己感兴趣的事件,添加方法即可。
接下来在Activity中,添加观察者
class LifecycleActivity2 : AppCompatActivity() {
private lateinit var chronometer: MyChronometer
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lifecycle2)
chronometer = findViewById(R.id.chronometer)
lifecycle.addObserver(chronometer)
}
}
完成了同样的功能,但使用Lifecycle后,Activiy中的代码清晰了很多,MyChronometer也达到了我们的目标,根据LifecycleOwner的生命周期变化实现了自管理。
解耦Service和组件
假设我们需要在后台服务中监听当前的位置信息,很容易想到通过Service来实现,在Service的onCreate中开始监听服务,在onDestroy中结束监听。但如果同时有多个需要在后台进行的事情,所有事情都需要在onCreate中开始、在onDestroy中结束,我们又会陷入到第一个例子中的困境,我们的任务不得不依赖Service的生命周期回调方法。幸好Jetpack中为我们提供了解决方案,那就是LifecycleService,下面我们看看怎样通过它来实现后台的位置监听。
首先创建MyLocationObserver类,它需要实现LifecycleObserver,做为生命周期的观察者。
class MyLocationObserver(private val context: Context) : LifecycleObserver {
private lateinit var locationManager: LocationManager
private lateinit var myLocationListener: MyLocationListener
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun startGps() {
locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
myLocationListener = MyLocationListener()
// 省略了权限判断
Log.d("==##", "start location")
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 3000, 1f, myLocationListener
)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun stopGps() {
Log.d("==##", "stop location")
locationManager.removeUpdates(myLocationListener)
}
class MyLocationListener : LocationListener {
override fun onLocationChanged(location: Location) {
Log.d("==##", "${location.latitude} ${location.longitude}")
}
}
}
在这个类中有两个主要的方法startGps和stopGps,它们添加注解分别是,@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)和@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY),表明它们关心的Service的生命周期事件是ON_CREATE和ON_DESTROY。startGps中实例化LocationManager并开启位置监听,stopGps移除位置监听器。
接下来是MyLocationService的实现
class MyLocationService : LifecycleService() {
init {
Log.d("==##", "MyLocationService")
val observer = MyLocationObserver(this)
lifecycle.addObserver(observer)
}
}
在MyLocationService的init块中,实例化MyLocationObserver,然后将其添加为观察者。当MyLocationService的生命周期发生变化时,一旦触发了MyLocationObserver感兴趣的事件后,MyLocationObserver相应的方法就会被回调。从而实现了MyLocationService和定位功能的解耦。
监听应用程序生命周期
经常有这样的需求,统计用户在app内停留的总时长,我记得我最开始是通过实现LifecycleCallback接口,在应用第一个Activity进入时开始计时,最后一个一个Activity离开时结束计时,需要自己处理里面的逻辑。现在Jetpack为我们提供了ProcessLifecycleOwner,实际上也是帮助开发者封装了LifecycleCallback,下一节讲源码分析的时候再细说。下面我们先看看用法
首先定义MyApplicationObserver,它实现了LifecycleObserver接口
/**
* 针对整个应用程序的监听 与Activity数量无关
*/
class MyApplicationObserver : LifecycleObserver {
/**
* 只会调用一次
*/
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate() {
Log.d("==##", "ON_CREATE")
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
Log.d("==##", "ON_START")
// 计时开始
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
Log.d("==##", "ON_RESUME")
}
/**
* 应用退到后台才会调用
*/
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
Log.d("==##", "ON_PAUSE")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
Log.d("==##", "ON_STOP")
// 计时结束
}
/**
* 永远不会调用
*/
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
Log.d("==##", "ON_DESTROY")
}
}
ProcessLifecycleOwner这个类的描述是这样的:
它为整个程序进程提供生命周期相关的支持,你可以认为它是所有Activity组合的LifecycleOwner,但是Lifecycle.Event#ON_CREATE只会回调一次,而Lifecycle.Event#ON_DESTROY一次也不会回调。当第一个Activity执行onStart和onResume的时候Lifecycle.Event#ON_START和Lifecycle.Event#ON_RESUME事件会被分发,当最后个Activity执行onPause和onStop的时候Lifecycle.Event#ON_PAUSE和Lifecycle.Event#ON_STOP事件会被分发。ON_PAUSE和ON_STOP事件的分发会有延迟,以保证当Activity因为配置变更重建时不会发任何事件。
Lifecycle源码分析
Activity/Fragment
LifecycleService
ProcessLifecycleOwner
文中代码的链接在这里
参考资料: 动脑学院