Jetpack系列之Lifecycle

180 阅读5分钟

简介

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的生命周期变化。代码中还有两个方法值得注意,startMeterstopMeter,它们的注解分别是@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}")
    }
  }
}

在这个类中有两个主要的方法startGpsstopGps,它们添加注解分别是,@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_STARTLifecycle.Event#ON_RESUME事件会被分发,当最后个Activity执行onPause和onStop的时候Lifecycle.Event#ON_PAUSELifecycle.Event#ON_STOP事件会被分发。ON_PAUSE和ON_STOP事件的分发会有延迟,以保证当Activity因为配置变更重建时不会发任何事件。

Lifecycle源码分析

Activity/Fragment

LifecycleService

ProcessLifecycleOwner

文中代码的链接在这里

参考资料: 动脑学院