简介
在 Android 系统中,有很多系统组件具备生命周期,比如Activity
、Fragment
、Service
...很多时候,我们都必须在系统组件的相应生命周期中执行自定义组件的相关逻辑,这样其实我们自定义的组件就与 Android 系统组件耦合在一起了。当我们有很多自定义组件都需要嵌入到系统组件的生命周期时,系统组件的代码就会急剧膨胀且严重与普通组件产生耦合,不利于功能扩展,违背设计模式开闭原则...
究其原因,非常简单,就是我们自定义的组件无法感知宿主系统组件生命周期,因此才会产生耦合。Android 开发团队也意识到这个问题,于是在 Jetpack Architecture 中,提供了一种可以感知系统组件生命周期的组件:Lifecycle
,借助该组件,我们的普通组件就具备感知宿主系统组件生命周期能力,这样就解耦了普通组件与系统组件之间的耦合。
Lifecycle
的基本原理是:采用观察者模式,系统组件作为被观察者(LifecycleOwner
),我们自定义的普通组件作为观察者(LifecycleObserver
),只需在感兴趣的系统组件注册自定义普通组件,则当相应宿主系统组件生命周期发生变化时,普通组件就能感知到。
目前Lifecycle
可以感知的系统组件(即已实现LifecycleOwner
接口的系统组件)包括:Activity
、Fragment
、Service
和Application
,具体感知方法参见下文。
依赖引入
Lifecycle
位于 AndriodX appcompat 包中,具体依赖添加如下:
implementation 'androidx.appcompat:appcompat:1.2.0'
感知 Activity
Activity
应当是最常被普通组件进行感知的系统组件,其具体生命周期感知方法如下步骤所叙:
-
首先自定义一个普通组件,让其实现接口
LifecycleObserver
,作为观察者,具备生命周期感知能力:inline val <reified T> T.TAG: String get() = T::class.java.simpleName class MyComponent : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun init() { Log.v(TAG, "initialize...") } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun release() { Log.v(TAG, "release...") } }
这里我们的自定义普通组件为
MyComponent
,由于其实现了LifecycleObserver
接口,因此其实一个观察者,相应系统组件的生命周期感知通过注解OnLifecycleEvent
进行指定,完整的生命周期感知事件定义枚举类Lifecycle.Event
中,具体内容如下表所示:生命周期事件 描述 ON_CREATE
对应 onCreate
事件ON_START
对应 onStart
事件ON_RESUME
对应 onResume
事件ON_PAUSE
对应 onPause
事件ON_STOP
对应 onStop
事件ON_DESTROY
对应 onDestroy
事件ON_ANY
对应上述所有事件 注:
Lifecycle
中除了通过注解@OnLifecycleEvent
监听宿主组件生命周期外,还可通过继承DefaultLifecycleObserver
或FullLifecycleObserver
,只需覆写相应的生命周期方法即可,此处不再赘述。
注:默认情况下,基于注解的方式采用的是反射进行回调,效率相对差些,因此最好添加一个编译期处理器lifecycle-compiler
,消除反射调用。使能编译期注解处理只需为模块的build.gradle
配置如下内容即可:// 导入编译期注解处理器 apply plugin: 'kotlin-kapt' dependencies { def lifecycle_version = "2.2.0" // Annotation processor kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" }
此时,被
@OnLifecycleEvent
注解的方法就不能声明为private
的。 -
在系统组件(此处是
Activity
)中注册自定义普通组件:class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 注册组件:MyComponent this.lifecycle.addObserver(MyComponent()) } }
在 AndroidX 中,其
ComponentActivity
已经默认实现了LifecycleOwner
:package androidx.activity; ... public class ComponentActivity extends androidx.core.app.ComponentActivity implements LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner, OnBackPressedDispatcherOwner { private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this); ... @NonNull @Override public Lifecycle getLifecycle() { return mLifecycleRegistry; } }
而
AppCompatActivity
间接继承自ComponentActivity
,所以我们自定义的MainActivity
默认可被观察。
注:如果项目仍未迁移到 AndroidX,还是采用 Support 库,那么可以让自定义Activity
继承SupportActivity
,因为SupportActivity
本身已实现了接口LifecycleOwner
。 -
以上,就完成了自定义普通组件感知
Activity
生命周期,运行程序后关闭应用,可看到如下日志:$ adb logcat -v time | rg MyComponent 03-14 23:28:06.049 V/MyComponent(14836): initialize... 03-14 23:29:51.886 V/MyComponent(14836): release...
说明我们自定义组件已经成功感知到
MainActivity
的生命周期了。
感知 Fragment
在 AndroidX 新版本中,Fragment
同样以默认实现了接口LifecycleOwner
:
package androidx.fragment.app;
...
public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
ViewModelStoreOwner, SavedStateRegistryOwner {
...
LifecycleRegistry mLifecycleRegistry;
...
@Override
@NonNull
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
...
}
因此,感知Fragment
的生命周期与感知Activity
生命周期方法如出一辙,这里简单介绍下:
-
首先创建一个
Fragment
,并设置相应布局:-
Fragment
布局文件:
<!--layout/fragment_mine.xml--> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:text="This is a Fragment" android:textSize="24sp" /> </LinearLayout>
- 自定义
Fragment
:
class MyFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_mine, container, false) } }
-
-
MainActivity
布局中添加该自定义Fragment
:<!--layout/activity_main.xml--> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <fragment <!-- 不能省略 id --> android:id="@+id/myfragment" <!-- 指定加载的 Fragment --> android:name="com.yn.jetpackarchdemo.fragment.MyFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
-
将自定义组件
MyComponent
注册到MyFragment
中,这里通过在Fragment.onAttach(..)
方法内进行注册:class MyFragment : Fragment() { override fun onAttach(context: Context) { super.onAttach(context) // 注册 this.lifecycle.addObserver(MyComponent()) } override fun onCreateView(...): View? {...} }
以上,就完成了自定义组件感知
Fragment
生命周期全过程。
感知 Service
如果要实现感知Service
生命周期,解耦Service
和自定义普通组件,可使用LifecycleService
:
package androidx.lifecycle;
...
public class LifecycleService extends Service implements LifecycleOwner {
private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);
...
@Override
@NonNull
public Lifecycle getLifecycle() {
return mDispatcher.getLifecycle();
}
}
可以看到,LifecycleService
继承了Service
并且实现了LifecycleOwner
。
-
首先,在使用
LifecycleService
前,需要先添加依赖:def lifecycle_version = '2.3.0' implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
-
创建一个普通组件且实现
LifecycleObserver
,使能观察者身份。这里我们直接使用上文的MyComponent
即可。 -
创建一个
MyService
类,继承LifecycleService
,这样我们定义的系统组件就可以作为一个被观察者,其他普通组件通过向MyService
注册即可感知MyService
生命周期:class MyService : LifecycleService() { init { // 注册 this.lifecycle.addObserver(MyComponent()) } }
记得在 AndroidManifest.xml 中注册
MyService
:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yn.jetpackarchdemo"> <application ... <service android:name=".service.MyService" /> </application> </manifest>
-
其实以上就已经完成了,这里为了能进行测试,我们修改下
MainActivity
的布局:<!-- layout/activity_main.xml --> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/startServiceBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="startService" /> <Button android:id="@+id/stopServiceBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="stopService" /> </LinearLayout>
这里定义了两个按钮,分别用于启动
Service
和停止Service
,具体代码如下:class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 启动 Service this.startServiceBtn.setOnClickListener { this.startService(Intent(this, MyService::class.java)) Toast.makeText(this, "startService done!", Toast.LENGTH_SHORT).show() } // 退出 Service this.stopServiceBtn.setOnClickListener { this.stopService(Intent(this, MyService::class.java)) Toast.makeText(this, "stopService done!", Toast.LENGTH_SHORT).show() } } }
运行程序,依序点击以上两个按钮,就可看到效果。
感知 Application
很多时候,我们可能想要知道当前应用程序是处于前台还是后台,或者当应用在进行前后台切换时,普通组件能感知到,此时,可以借助ProcessLifecycleOwner
,该类是Lifecycle
提供的可让我们感知应用程序生命周期的组件(也即感知Application
生命周期),具体操作步骤如下:
-
首先,导入相关依赖:
def lifecycle_version = '2.3.0' implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
-
自定义一个普通组件,实现接口
LifecycleObserver
,并覆写相应生命周期方法:private const val TAG = "MyAppComponent" class MyAppComponent : LifecycleObserver { // ON_CREATE 在整个应用程序运行期间只会调用一次 @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun onCreate() { Log.v(TAG, "onCreate") } // 程序处于前台 @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onStart() { Log.v(TAG, "onStart") } // 程序处于前台 @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun onResume() { Log.v(TAG,"onResume") } //程序处于后台 @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun onPause() { Log.v(TAG,"onPause") } // 程序处于后台 @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onStop() { Log.v(TAG,"onStop") } // Application 不会分发该事件,因此 ON_DESTROY永远不会被调用 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun onDestroy() { Log.v(TAG, "onDestroy") } }
-
自定义一个
Application
类,并使用ProcessLifecycleOwner
注册相应普通组件,完成监听绑定:class MyApplication : Application() { override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get().lifecycle.addObserver(MyAppComponent()) } }
记得在 AndroidManifest.xml 中注册我们自定义的
Applicatioin
:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yn.jetpackarchdemo"> <application android:name=".MyApplication" ... /application> </manifest>
-
以上,就完成了对应用程序生命周期的感知。
借助ProcessLifecycleOwner
,我们就能很方便感知到应用程序前后台切换动作,当程序首次启动时,会依次触发ON_CREATE
、ON_START
和ON_RESUME
生命周期事件,此时程序处于前台;当程序从前台切到后台时,会依次触发ON_PAUSE
和ON_STOP
事件(注:这两个事件响应会相对迟缓,因为必须让步于屏幕旋转而导致的Activity
重新创建问题,即屏幕旋转不会导致这两个事件被误触发);后续如果程序从后台又重新返回前台时,此时就只会依序触发ON_START
和ON_RESUME
事件。因此,在应用程序的整个运行期间,ON_CREATE
只会被调用一次(首次启动时),ON_DESTROY
永远不会被调用。
主动获取系统组件当前生命周期
上文我们所介绍的普通组件都是被动的感知系统组件生命周期,其实Lifecycle
也提供了相应方法来让我们主动获取当前生命周期,该接口为Lifecycle.getCurrentState()
,其返回一个State
枚举实例,表示当前系统组件的生命周期,具体内容如下:
@SuppressWarnings("WeakerAccess")
public enum State {
DESTROYED,
INITIALIZED,
STARTED,
RESUMED;
// 当前状态是否大于或等于参数状态
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
Lifecycle
维护并追踪记录了系统组件生命周期状态相关信息,在系统组件整个生命周期流程过程中,Lifecycle
分别对应的生命周期状态维护如下图所示:
简单来说,当获取的生命周期状态为CREATED
时,表示系统组件的onCreate
方法已执行结束(即ON_CREATE
事件结束),但onStart()
方法还未执行。同理,当获取生命周期状态为STARTED
时,说明系统组件的onStart()
方法以运行结束,但onResume()
方法仍未执行...
为普通组件添加主动查询生命周期方法其实很简单,只需将系统组件的Lifecycle
实例传递给普通组件即可:
// 普通组件
class MyComponent(private val lifecycle: Lifecycle) : LifecycleObserver {...}
// 系统组件
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 注册
this.lifecycle.addObserver(MyComponent(this.lifecycle))
}
当普通组件覆写的相应生命周期方法内,存在回调函数时,此时运行回调函数前,就很有必要主动查询下当前系统组件所处生命周期状态,避免因生命周期不当而导致相关执行出错:
class MyComponent(private val lifecycle: Lifecycle) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun init() {
thread {
// 模拟耗时任务
Thread.sleep(TimeUnit.SECONDS.toMillis(2))
if(this.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// do something
}
}.start()
}
}
自定义生命周期可被感知的系统组件
前面介绍的所有系统组件都是默认已内置了生命周期感知共享功能,而如果我们自己想手动实现一个生命周期可被感知的组件,其实也很简单,执行为自定义系统组件提供一个Lifecycle
即可,具体示例如下所示:
class MyActivity : Activity(), LifecycleOwner {
private lateinit var lifecycleRegistry: LifecycleRegistry
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleRegistry = LifecycleRegistry(this)
lifecycleRegistry.markState(Lifecycle.State.CREATED)
}
public override fun onStart() {
super.onStart()
lifecycleRegistry.markState(Lifecycle.State.STARTED)
}
override fun getLifecycle(): Lifecycle {
return lifecycleRegistry
}
}
Android 系统自带的Activity
本身不具备生命周期被感知功能,我们只需为其添加一个Lifecycle
实例,维护与分发其生命周期即可:
-
首先为
MyActivity
创建一个Lifecycle
实例,负责维护与管理其生命周期相关信息。这里使用的是LifecycleRegistry
,该类继承自Lifecycle
,并实现了相应的生命周期状态管理与维护逻辑,方便我们使用。 -
在
MyActivity
每个生命周期函数中,LifecycleRegistry
都进行了标记,以实现生命周期被感知功能。 -
最后,
MyActivity
实现了接口LifecycleOwner
,该接口是一个单抽象方法接口,其抽象方法为getLifecycle()
,作用就是返回系统组价的内置Lifecycle
,方便外部普通组件进行注册(被动感知生命周期)与主动查询状态等操作。
网友评论