Jetpack组件之LifeCycle

Jetpack组件之LifeCycle

八归少年 2,333 2021-03-26

Android Jetpack组件系列文章:
Android Jetpack组件(一)LifeCycle
Android Jetpack组件(二)Navigation
Android Jetpack组件(三)ViewModel
Android Jetpack组件(四)LiveData
Android Jetpack组件(五)Room
Android JetPack组件(六)DataBinding
Android Jetpack组件(七)Paging
Android Jetpack组件(八)WorkManager
Android Jetpack组件(九)DataStore
Android Jetpack组件(十)App Startup
Android Jetpack组件(十一)Compose

首语

3月4日,Google重磅发布了 Flutter 2 !作为 Flutter 的重大升级,使用 Flutter 2 开发者可以用相同的代码,把使用 Flutter 开发的应用发布到五个操作系统:iOS,Android,Windows,macOS 和 Linux;以及运行到 Chrome 、 Firefo, Safari 或 Edge等浏览器的 Web 版本上,Flutter 甚至还可以嵌入到 Cars, TVs 和智能家电中。
作为一个Flutter开发者,也马上下载了Flutter 2.0 sdk,并将自己的Flutter项目运行到Chrome上,效果很好,就是代码中有些差别,Web端对图片以及dart的io包不支持等等。具体差异可以去Flutter官网查看。贴一张web端效果图。
Flutter 2

介绍

2017年Google I/O大会上,Google推出了AAC(Android Architecture Components),其中包含了LiveData、ViewModel和Room等专门为架构所设计的组件。AAC也可以被当作Jetpack的前身。在2018年Google I/O大会上,Google在AAC的基础上推出了Jetpack。

Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。
Jetpack主要包含以下四个方面,分别是架构(Architecture)、界面(UI)、行为(Behavior)和基础(Foundation)。

  • Architecture组件可帮助您设计健壮,可测试和可维护的应用程序。
  • Foundation组件提供了跨领域功能,例如向后兼容性,测试和Kotlin语言支持。
  • Ul组件提供了小部件和帮助程序,使应用程序不仅简单易用,而且使用起来令人愉快。
  • Behavior组件可帮助应用与标准的Android服务集成,例如通知,权限,共享和助手。
    其中的Architecture组件是我们关注的重点。下面会对其中的组件进行展开学习。下面的这张图是Jetpack刚发布时候的图,现在Jetpack的组件已经不止图中的这些了。详细组件见Android Jetpack所有库

Jetpack

优点

  1. 遵循最佳做法
    Android Jetpack 组件采用最新的设计方法构建,具有向后兼容性,可以减少崩溃和内存泄露。
  2. 消除样板代码
    Android Jetpack 可以管理各种繁琐的Activity(如后台任务、导航和生命周期管理),以便可以专注于打造出色的应用。
  3. 减少不一致
    这些库可在各种 Android 版本和设备中以一致的方式运作,助您降低复杂性。

AndroidX 概览

AndroidX 命名空间中的工件包含 Android Jetpack库。与support库一样,AndroidX命名空间中的库与 Android 平台分开提供,并向后兼容各个 Android 版本。
如果要将项目迁移到AndroidX,在Android Studio的菜单栏中选择Refactor—>Migrate to AndroidX。完成之后,打开gradle.properties文件,可以看到这两行代码:

# 表示是否使用AndroidX
android.useAndroidX=true
# 表示是否将第三方库迁移到AndroidX
android.enableJetifier=true

对于新版本的Android Studio已经默认支持AndroidX了,不需要如上操作。

LifeCycle

我们经常要在页面的onCreate()中对组件初始化,在onPause()中停止组件,在onDestory()中对组件进行回收。这样的工作繁琐且代码难以维护,还会引发内存泄漏。
为此,Google提供了LifeCycle作为解决方案。LifeCycle可以帮助开发者简历可感知生命周期的组件,通过使用生命周期感知型组件,您可以将依赖组件的代码从生命周期方法移入组件本身中,从而降低了模块间的耦合性和内存泄漏的可能性,编写出更精简的代码且易于维护。

LifeCycle的原理

Lifecycle 是一个类,用于存储有关组件(如 ActivityFragment)的生命周期状态的信息,并允许其他对象观察此状态。
Lifecycle 使用两种主要枚举跟踪其关联组件的生命周期状态:

  • 事件(Event)
    从框架和 Lifecycle 类分派的生命周期事件。这些事件映射到ActivityFragment中的回调事件。
 public enum Event {

        ON_CREATE,
      
        ON_START,
       
        ON_RESUME,
       
        ON_PAUSE,
       
        ON_STOP,
       
        ON_DESTROY,
        
        ON_ANY
 }
  • 状态(state)
    由 Lifecycle 对象跟踪的组件的当前状态。
public enum State {
      
        DESTROYED,

        INITIALIZED,
        
        CREATED,

        STARTED,

        RESUMED;
//比较此状态是否大于或等于给定状态
public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
}

这些我们都可以从Lifecycle类的源码中能看到,具体说明如下图所示。
LifeCycle
Jetpack给我们提供了两个类:LifeCycleOwner(被观察者)和LifeCycleObserver(观察者)。通过观察者模式实现对页面生命周期的监听。
我们在ComponentActivity的源码中可以看到它实现了LifecycleOwner接口,接口中只有一个getLifeCycle(),LifeCycle正是通过该方法实现观察者模式,源码中已经实现了被观察者实现的那部分。

 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;
  }

我们监听 Atctivity的生命周期时,只需要实现观察者那一部分的代码,即让自定义组件实现LifecycleObserver接口即可。

public class MyObserver implements LifecycleObserver {
	//当Activity执行onResume()时,该自动调用
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void connectListener() {
        ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void disconnectListener() {
        ...
    }
}

Activity中,只需要使用以下代码,将观察者和被观察者绑定起来,不用再担心Activity生命周期变化对组件带来的影响。

getLifecycle().addObserver(new MyObserver());

LifecycleService

Android中除了ActivityFragment有生命周期外,还有一个重要的组件Service,为了方便对Service生命周期的监听,Android提供了LifecycleService类,该类继承于Service,并实现了LifecycleOwner接口。和ActivityFragment类似,也有一个getLifecycle()供我们调用,部分源码如下。

public class LifecycleService extends Service implements LifecycleOwner {
    private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);
    
    @Override
    @NonNull
    public Lifecycle getLifecycle() {
        return mDispatcher.getLifecycle();
    }
}

使用LifecycleService时,我们需要添加如下依赖:

implementation "androidx.lifecycle:lifecycle-service:2.3.0"

使用和Activity中的类似,在Service中绑定观察者,在自定义Observer中实现事件的绑定。使用LifecycleService很好的实现了组件与Service之间的解耦,在其内部自行管理生命周期带来的变化。

ProcessLifecycleOwner

具有生命周期的组件除了ActivityFragmentService,还有Application。很多时候我们想知道应用程序处于前台还是后台,或者后台回到前台可以得到通知。为此,LifeCycle提供了一个ProcessLifecycleOwner类,方便我们知道整个应用程序的生命周期情况。
使用ProcessLifecycleOwner时,我们需要添加如下依赖:

implementation "androidx.lifecycle:lifecycle-process:2.3.0"

ProcessLifecycleOwner的使用方式和ActivityFragmentService类似,其本质都是观察者模式,在Application中绑定观察者,在自定义Observer中绑定事件。
有了ProcessLifecycleOwner,我们可以方便获取到应用生命周期的变化,在其中做一些业务操作,减少了项目代码的耦合性。但需要注意的是:

  1. ProcessLifecyoleowner是针对整个应用程序的监听,与Activity数量无关。
  2. Lifecycle.Event.ON CREATE 只会被调用一次,而Lifecycle.Event.ON_DESTROY 永远不会被调用。
  3. 当应用程序从后台回到前台,或者应用程序被首次打开时,会依次调用Lifecycle.Event.ON_STARTLifecycle.Event.ON_RESUME
  4. 当应用程序从前台退到后台(用户按下 Home 键或任务菜单键),会依次调用 Lifecycle.Event.ON PAUSELifecycle.Event.ON_ STOP

ON_STOP 事件

如果 Lifecycle 属于AppCompatActivityFragment,那么调用 AppCompatActivityFragmentonSaveInstanceState()时,Lifecycle 的状态会更改为 CREATED 并且会分派ON_STOP事件。在FragmentActivity的源码中可以看到。

 markFragmentsCreated();
 mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);

 private void markFragmentsCreated() {
        boolean reiterate;
        do {
            reiterate = markState(getSupportFragmentManager(), Lifecycle.State.CREATED);
        } while (reiterate);
    }

 private static boolean markState(FragmentManager manager, Lifecycle.State state) {
        boolean hadNotMarked = false;
        Collection<Fragment> fragments = manager.getFragments();
        for (Fragment fragment : fragments) {
            if (fragment == null) {
                continue;
            }
            if (fragment.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
                fragment.mLifecycleRegistry.setCurrentState(state);
                hadNotMarked = true;
            }

            if (fragment.getHost() != null) {
                FragmentManager childFragmentManager = fragment.getChildFragmentManager();
                hadNotMarked |= markState(childFragmentManager, state);
            }
        }
        return hadNotMarked;
  }

通过onSaveInstanceState() 保存 Fragment 或AppCompatActivity的状态后,其界面被视为不可变,直到调用ON_START。如果在保存状态后尝试修改界面,很可能会导致应用的导航状态不一致,因此应用在保存状态后运行 FragmentTransaction时,FragmentManager会抛出异常。
AppCompatActivityonStop() 会在onSaveInstanceState()之后调用,这样就会留下一个缺口,即不允许界面状态发生变化,但 Lifecycle 尚未移至 CREATED 状态。
为防止出现这个问题,beta2 及更低版本中的 Lifecycle 类会将状态标记为CREATED而不分派事件,这样一来,即使未分派事件(直到系统调用onStop()),检查当前状态的代码也会获得实际值。

用例

  1. 位置更新之间切换。
  2. 开始和停止视频缓冲。
  3. 开始和停止网络连接。
  4. 暂停和恢复动画可绘制资源。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.yanghujun.com/archives/lifecycle