1. 简介
为了应用的安全,经常会有从后台切回前台时进行软件确认等安全确认处理的需求。如果是以前的话,这个需求其实是挺难实现的。 但自从Google推出Lifecycle组件以后,这个需求就简单了很多。Lifecycle除了感知从后台切回前台以外, 利用这个组件可以更简单的实现复杂的处理生命周期的操作。这篇只讲述如何实现感知从后台切回前台时的生命周期。
2. Lifecycle组件
2.1 介绍
用Lifecycle组件可以感知Activity和Fragment的生命周期。
- 该组件的实现方式是观察者模式。在
生命周期拥有者和生命周期的观察者之间建立观察与被观察的关系。当生命周期拥有者的生命周期发生变化时会通知观察者生命周期观察者,观察者收到通知后会进行各种处理。 - 可以方便获取
生命周期拥有者的生命周期。
生命周期使用两个主要枚举来跟踪相关组件的生命周期:
Event: 从框架和LifeCycle类派发的生命周期事件。这些事件映射到Activity和Fragment中的回调事件。State: 有LifeCycle对象跟踪的组件的当前状态。
2.2 使用场景
- 可以集中处理生命周期事件,不用反复在不同的Activity中写生命周期事件(如解除广播)。
- 可以实现感知整个应用的生命周期。
3. LifeCycle的使用
3.1 添加到依赖库
根据自己的需要添加LifeCycle的依赖到自己的项目中。
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - just ViewModel
implementation "android.arch.lifecycle:viewmodel:$lifecycle_version" // use -ktx for Kotlin
// alternatively - just LiveData
implementation "android.arch.lifecycle:livedata:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
// alternately - if using Java8, use the following instead of compiler
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"
// optional - ReactiveStreams support for LiveData
implementation "android.arch.lifecycle:reactivestreams:$lifecycle_version"
3.2 LifeCyleOwner
LifeCycleOwner是生命周期的观察者。会根据收到的通知进行相应处理。LifeCycleOwner的接口很简单,如下:
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
在Activity和Fragment中添加生命周期的观察者。
lifecycle.addObserver(AppLifecycleObserver(object:AppLifecycleCallback(){
// Do something
}))
3.3 LifeCycleObserver
LifeCyclObserver是生命周期的被观察者。在这里需要定义我们在生命周期的各个阶段中进行的操作。我们需要通过LifeCycle的注解来标注该方法是在哪个生命周期被调用。如下:
class AppLifecycleObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
// Do something
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
// Do something
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate() {
// Do something
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
// Do something
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onDestroy() {
// Do something
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
// Do something
}
// 所有的生命周期都会调用这个方法
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
fun onAny() {
// Do something
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)的注解如其名,会在所有的生命周期阶段都会被调用。
4. 应用切换前后台的生命周期感知
4.1 实现LifeCyCleObserver类
首先我们要实现当感知到切回前台时的操作,所以需要实现的处理写入到LifeCycleObserver中。 在这里我们加入了回调,这些回调将会在Application类中实现。
class AppLifecycleObserver(val callback: AppLifecycleCallback) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
callback.onStart()
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
callback.onPause()
}
}
当然还有创建回调类。
interface AppLifecycleCallback {
fun onStart()
fun onPause()
}
4.2 LifeCycleOwner
接下来是在Android中实现LifeCycleOwner类。还有要设置一个Flag,用于记录前后台的切状态。
在这里说明一下, 为什么会在onStart中进行onForeground操作原因,而不是onResume。
因为从后台切回前台时,都是先调用Activity的生命周期,然后再调用Android的。即Acitivty的OnResume() -> Application的onResume()。这种情况如果我们在Application的onResume中进行onForeground操作,Activity会拿到onBackground的flag。
所以如果想在Activity的onResume中判断切回前台的状态,则需要在Application中比onResume状态之前的状态中实现。
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver(object :
AppLifecycleCallback {
override fun onStart() {
onForeground()
Log.d(TAG, "onStart")
}
override fun onPause() {
onBackground()
Log.d(TAG, "onPause")
}
}))
}
fun getAppStatus(): Boolean {
return isAppActive
}
fun onBackground() {
isAppActive = false
}
fun onForeground() {
isAppActive = true
}
在Application中只能通过ProcessLifecycleOwner中获得lifecycle。
4.3 在具体的Acitivty中获取Flag
虽然可以在Android实现感知的具体操作, 但实际需求是不需要所有的Activity都需要感知。这个时候可以在Activity中获取Flag,根据Flag进行相关处理。
override fun onResume() {
super.onResume()
Log.d("MainActivity", "onResume")
val app = application as AndroidApplication
Log.d("MainActivity", app.getAppStatus().toString())
if (app.getAppStatus()) {
Log.d("MainActivity", "onResume work")
Toast.makeText(this, "App is in Foreground", Toast.LENGTH_LONG).show()
}
}
4.4 实际效果
5. 总结
LifeCycleObserver应该避免引用Context和View等, 防止发生内存泄露。应对这个问题可以使用回调,即在LifeCycleObserver中加入回调,在Activity和Fragment中实现。- 虽然
LifeCycle很好用,但不要滥用。 如果项目中不需要大量的生命周期处理,就不需要使用这个组件。
github: github.com/HyejeanMOON…