Jetpack组件之LifeCycle

2022-06-29 15:41:15 浏览数 (1)

首语

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端效果图。

介绍

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所有库。

优点

  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文件,可以看到这两行代码:

代码语言:javascript复制
# 表示是否使用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中的回调事件。
代码语言:javascript复制
 public enum Event {

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

        INITIALIZED,
        
        CREATED,

        STARTED,

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

这些我们都可以从Lifecycle类的源码中能看到,具体说明如下图所示。

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

代码语言:javascript复制
 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接口即可。

代码语言:javascript复制
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生命周期变化对组件带来的影响。

代码语言:javascript复制
getLifecycle().addObserver(new MyObserver());
LifecycleService

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

代码语言:javascript复制
public class LifecycleService extends Service implements LifecycleOwner {
    private final ServiceLifecycleDispatcher mDispatcher = new ServiceLifecycleDispatcher(this);
    
    @Override
    @NonNull
    public Lifecycle getLifecycle() {
        return mDispatcher.getLifecycle();
    }
}

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

代码语言:javascript复制
implementation "androidx.lifecycle:lifecycle-service:2.3.0"

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

ProcessLifecycleOwner

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

代码语言:javascript复制
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的源码中可以看到。

代码语言:javascript复制
 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. 暂停和恢复动画可绘制资源。

0 人点赞