这是我参与更文挑战的第4天,活动详情查看: 更文挑战
对于刚接触生命周期组件的小伙伴来说,对Lifecycle、LifecycleOwner、ViewLifecycleOwner、LifecycleScope、ViewModelScope、repeatOnLifecycle等这些概念可能会有点分不太清。为便于理解,本文对这几个概念会做初步讲解,暂未涉及深入的实现原理。
一、Lifecycle
在Activity中我们知道有其对应的生命周期如onResume、onDestory,往往我们需要再对应的生命周期里去注册或者反注册一些功能,如果页面多那每个页面都需要添加,当然也可以放到BaseActivty里,但这就约束了我们的Activity必需要继承BaseActivity。
而生命周期感知组件既是可以感知Activty生命周期的变化,既是Activty触发对应的生命周期时,组件里对应的方法就会被触发执行。
1:没有使用生命周期组件
引用官方示例,我们需要在onStart里开启定位服务,onStop里关闭定位,下面是普通写法:
internal class MyLocationListener(
private val context: Context,
private val callback: (Location) -> Unit
) {
fun start() {
//开启定位服务
}
fun stop() {
//断开定位服务
}
}
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this) { location ->
//更新UI
}
}
public override fun onStart() {
super.onStart()
myLocationListener.start()
}
public override fun onStop() {
super.onStop()
myLocationListener.stop()
}
}
这种写法存在的问题:
- 如开始提到的,如果较多页面需要开启、关闭,则每个页面都需要写。当然也可以放到BaseActivity中,但这就限制了普通Activty的使用
- 这里只提到定位功能需要在onStart、onStop里面处理,实际应用可能会有更多功能在onStart、onStop里面处理,造成onStart、onStop里面代码臃肿,难以维护
- 比如onStop里面执行一些释放操作,可能会导致Activty存在的时间比我们实际需要使用的时间更长
- 管理不当容易造成内存泄漏
因此引入Lifecycle来解决此类问题,让我们的组件具备生命周期感知功能
2:使用生命周期组件(Lifecycle)
Lifecycle 是一个类,可以理解为观察者的实现类(不过其为抽象类,由其子类如LifecycleRegistry实现),用于存储有关组件(如 activity 或 fragment)的生命周期状态的信息,并允许其他对象观察此状态。如以下示例:
- 观察者:MyObserver
- 被观察者:MainActivity,通过getLifecycle().addObserver添加观察者
这样被观察者就能够感知Activity的生命周期变化
依赖:
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")
class MyObserver(
private val context: Context,
private val lifecycle: Lifecycle,
private val callback: (Location) -> Unit
) : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
//connect
}
}
override fun onPause(owner: LifecycleOwner) {
//disconnect
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
getLifecycle().addObserver(MyObserver(this@MainActivity,lifecycle)) //生命周期组件添加MyObserver观察者
}
}
那getLifecycle().addObserver是怎样的呢,可以看LifecycleOwner
二、LifecycleOwner
这里先说下继承关系
LifecycleRegistry extends Lifecycle //观察者实现,其相关的方法,会在Activity、Fragment生命周期方法中被对应调用
Activity implements LifecycleOwner
Fragment implements LifecycleOwner //LifecycleOwner的实现方法getLifecycle()用来提供LifecycleRegistry对象
LifecycleOwner 是一个接口,如Activity、Fragment类里面就会实现该接口,用以提供生命周期组件(提供观察者模式的实现类)。通过getLifecycle()拿到生命周期组件对象,即可通过它添加观察者(示例可以看到LifecycleRegistry这个类里有个addObserver方法,用来添加观察者)
public interface LifecycleOwner {
Lifecycle getLifecycle();
}
public class LifecycleRegistry extends Lifecycle {
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
xxx
}
}
public class Fragment implements LifecycleOwner,xxx {
LifecycleRegistry mLifecycleRegistry;
@Override
@NonNull
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
实现自定义的LifecycleOwner(Fragment 和 Activity 已实现 LifecycleOwner 接口)
如果有一个自定义类并希望使其成为 LifecycleOwner,可以使用 LifecycleRegistry 类,但需要将事件转发到该类
public class LifecycleRegistry extends Lifecycle {
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
xxx
}
}
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
}
}
三、ViewLifecycleOwner
在Fragment里有LifecycleOwner它是针对Activity、Fragment的,而ViewLifecycleOwner如其名,是针对Fragment中View的LifecycleOwner
ViewLifecycleOwner的赋值在onCreateView之前,置空在onDestroyView之后
Fragment中View的生命周期与Fragment本身并不相同,Fragment入back stack的过程会执行onDestroyView但不执行之后的onDestroy与onDetach,而出back stack是从onCreateView开始执行,而没有之前的onAttach与onCreate
class FragmentViewLifecycleOwner implements HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner, ViewModelStoreOwner {
@NonNull
@Override
public Lifecycle getLifecycle() {
initialize();
return mLifecycleRegistry;
}
}
public class Fragment implements LifecycleOwner,xxx {
lateinit var lifecycleRegistry: LifecycleRegistry
FragmentViewLifecycleOwner mViewLifecycleOwner;
@Override
@NonNull
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
@MainThread
@NonNull
public LifecycleOwner getViewLifecycleOwner() {
if (mViewLifecycleOwner == null) {
throw new IllegalStateException("Can't access the Fragment View's LifecycleOwner when "
+ "getView() is null i.e., before onCreateView() or after onDestroyView()");
}
return mViewLifecycleOwner;
}
}
四、LifecycleScope
LifecycleScope,顾名思义,可以理解为Lifecycle里的协程作用域,每个 Lifecycle 对象都定义了 LifecycleScope,可以指定在特定的生命周期执行协程代码,在Lifecycle 被销毁时取消。
你可以通过 lifecycle.coroutineScope 或 lifecycleOwner.lifecycleScope 属性访问 Lifecycle 的 CoroutineScope
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
lifecycleScope.launch {
withContext(Dispatchers.IO) {
}
}
lifecycleScope.launch(Dispatchers.IO){
}
lifecycleScope.launch {
whenResumed {
}
}
lifecycleScope.launchWhenResumed {
}
lifecycleScope.launch
{
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
}
}
repeatOnLifecycle & lifecycle.whenXxx
lifecycle.launch: 即使处于后台,也一直会执行协程代码,生产者也保持活跃
repeatOnLifecycle: 可以指定在特定的生命周期执行协程协程代码,当不再该状态时就会取消协程块的执行。当程序处于后台时,视图层收集停止,数据生产者停止。
lifecycle.whenXxx: 可以指定在特定的生命周期执行协程协程代码,当不再该状态时就会暂停协程块的执行。当程序处于后台时,视图层收集暂停,数据生产者仍然活跃,可能会在后台持续发出不需要在屏幕上显示的数据项,从而将内存占满。
viewLifecycleOwner.lifecycleScope.launch{} 当应用程序处于后台时不会停止
lifecycleScope.launch {lifecycle.whenResumed {}} 应用程序处于后台时视图层收集暂停,生产者仍活跃,返回时从暂停处继续
lifecycleScope.launch {viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {}} 当应用程序处于后台时视图层收集停止,生产者停止,当它返回时从头开始
| State | 时机 |
|---|---|
| Lifecycle.State.CREATED | onCreate调用后,onStop调用之前 |
| Lifecycle.State.STARTED | onStart调用后, onPause调用之前 |
| Lifecycle.State.RESUMED | onResume调用后 |
五、ViewModelScope
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0'
如果 ViewModel 已清除,则在此范围内启动的协程都会自动取消