【译文】Android lifecycle-aware components codelab

原文地址:https://codelabs.developers.google.com/codelabs/android-lifecycles/#0
文中的图片都是引用上面链接,可能需要科学上网才能看到。

1.介绍

Components

Architecture Components是一组Android库,可以帮助你用一种健壮的、可测试的、可维护的方式来架构你的APP。

注意:Architecture Components库还是处于开发测试阶段。在发布稳定版之前,API接口可能变化,你可能会遇到稳定性和性能问题。

这个codelab介绍以lifecycle-aware architecture components方式去构建Anroid apps:

  • ViewModel - 提供一种方式来创建和查找对象,这个对象被绑定到特定的生命周期。ViewModel通常存储视图数据的状态,并与其他组件通信,例如处理业务逻辑的数据存储或域层。更多了解ViewModel,请关注ViewModel
  • LifecycleOwner/LifecycleRegistryOwner - LifecycleOwnerLifecycleRegistryOwner都是在LifecycleActivityLifecycleFragment类实现的接口。你可以向实现这些接口的所有者对象订阅其他组件,以观察所有者对象的生命周期变化。更多了解Lifecycle,请关注Handling Lifecycles
  • LiveData - 可以让你在APP的多个组件之间观察数据的变化,而不用在它们之间创建明确的、强引用的路径。LiveData遵循你APP组件复杂的生命周期,包括activities,fragments,services, 或者其他在你APP定义的LifecycleOwnerLiveData管理观察者的订阅,它暂停Stopped状态LifecycleOwner对象的订阅,取消Finished状态LifecycleOwner对象的订阅。更多了解LiveData,请关注LiveData

你将做什么

在这个codelab中,你会实现上述每个组件的例子。从一个简单的APP开始,通过一系列步骤添加代码,将各种architecture components集成在一起。

你需要准备什么

2.Step1 - 配置环境

首先下载整个codelab的项目代码,运行这个简单示例APP。

  1. 打开这个项目在Android Studio 2.3及以上
  2. 在手机或模拟器运行Step 1的运行配置

APP运行后显示与下面截图类似的屏幕


3. 旋转屏幕,注意时间器的重置

在这种场景中,你需要更新APP以在屏幕旋转时保持状态。你可以使用ViewModel因为这个类的实例可以在配置变化时存活,例如旋转屏幕。

3.Step2 - 添加ViewModel

在这一步,你将使用一个ViewModel在屏幕旋转时保存数据,解决前面步骤中所遇到的问题。在前面步骤中,运行了一个Activity,显示计时器。当配置变化,如屏幕旋转、Activity销毁,计时器将重置。

使用ViewMode,可以在Activity和Fragment的整个生命周期保存数据。就如前面步骤所表示,Activity是一个不好的选择去管理APP数据。当用户在操作APP时,Activity和Fragment是短生命周期的对象,会被频繁地创建和销毁。ViewModel也更适合管理与网络通讯相关的任务,以及数据处理和持久化。

使用ViewModel保存计时器的状态

打开ChronoActivity2,观察类中怎么使用ViewModel。

    ChronometerViewModel chronometerViewModel = ViewModelProviders.of(this).get(ChronometerViewModel.class);        

这引用一个LifecycleOwner的实例。只要LifecycleOwner的作用域还活着,那么这个架构保持ViewModel还存在。如果一个包含ViewModel的对象实例因配置变化被销毁,如屏幕旋转,那么ViewModel也不会被销毁。新的实例将重新绑定存在的ViewModel,就如下图所表示:

注意:Activity和Fragment的范围从created到finished(或terminated),你没必要受destroyed所迷惑。记住当设备旋转时,Activity被销毁,但是与Activity关联的ViewModel的实例还没有被销毁。

试一试

运行APP,确定当你执行下面任何一个操作时,计时器不会被重置:

  1. 旋转屏幕。
  2. 导航到另一个APP并返回。

但是,如果你或者系统退出了这个APP,那么计时器将重置。

注意:系统在内存保存ViewModel的实例,贯穿lifecycle拥有者的生命周期,如Fragment或Activity。系统不会保存ViewModel的实例在永久存储。

4.Step 3 - 使用LiveData封装数据

在这一步,你不需要上一步用到的chronometer计时器,而是采用一个普通的Timer计时器,每一秒更新UI。Timer是一个java.util类,可以用来周期性执行任务。你可以把Timer计时这个逻辑添加到LiveDataTimerViewModel类中,从而让Activity只需管理用户和UI之间的交互。

当Timer发出通知后,Activity更新UI。为了避免内存泄漏,ViewModel不要包含Activity的引用。例如,配置的变化,如屏幕旋转,可能会导致在ViewModel中的Activity引用被内存回收。而系统将保存ViewModel的实例,直到相应的Activity或者lifecycle拥有者不再存在。

注意:在ViewModel中存储Context或View的引用,将会导致内存泄漏。需要避免引用Context或View类实例的变量。onCleared方法可以用于解绑或者清理其他稍长生命周期类的引用,但不能用于清理Context或View类的引用。

你可以配置Activity或Fragment去观察数据源,当它变化时更新数据,而不是从ViewModel直接修改Views。这种方式叫做观察者模式。

注意:为了暴露数据作为被观察的对象,可以声明为LiveData类。

如果你使用过Data Binding Library或者其他响应式库,如RxJava。LiveData是一个具有生命周期的特殊被观察者类,只通知存活的观察者。

LifecycleOwner

ChronoActivity3是一个LifecycleActivity的实例,提供了生命周期的状态。下面是类的声明:

    public class LifecycleActivity extends FragmentActivity implements LifecycleRegistryOwner {...}

LifecycleRegistryOwner被用来绑定ViewModelLiveData实例的生命周期到Activity或Fragment中。与Fragment相对应的是LifecycleFragment

更新ChronoActivity

1、在ChronoActivity3类的subscribe()方法添加下面的code,创建一个订阅:

    mLiveDataTimerViewModel.getElapsedTime().observe(this, elapsedTimeObserver);

2、下一步,在LiveDataTimerViewModel类中设置新的elapsed time值。找到下面的备注:

    //TODO set the new value

替换上面的备注:

    mElapsedTime.setValue(newValue);

3、运行APP,并且在Android Studio打开Android Monitor。注意log更新每一秒,除非你导航到其他APP。如果你的设备支持多窗口模式,你可以试用它。旋转屏幕不会影响APP的行为。

注意:LiveData对象只有当Activity或者LifecycleOwner还存活着时才发送更新。如果你导航到其他APP,log信息会暂停直到你返回。当LiveData对象各自生命周期拥有者是STARTEDRESUMED状态时,它们只关心活跃的订阅。

5.Step4 - 订阅Lifecycle事件

很多Android组件和库需要你去做:

  1. 订阅,或者初始化组件或库
  2. 解绑,或者停止组件或库

如果上面的步骤失败,那么会导致内存泄漏或者奇怪的bug。

生命周期对象可以传递给具有生命周期的组件实例,保证实例知道现在生命周期的状态。

你可以使用下面的程序查询现在生命周期的状态:

    lifecycleOwner.getLifecycle().getCurrentState()

上面的程序返回一个状态,如Lifecycle.State.RESUMEDLifecycle.State.DESTROYED

那些实现了LifecycleObserver的生命周期对象,也可以在生命周期拥有者的状态里观察变化。

    lifecycleOwner.getLifecycle().addObserver(this);

你可以注解对象,让它在需要的时候调用相应的方法:

    @OnLifecycleEvent(Lifecycle.EVENT.ON_RESUME)
    void addLocationListener() { ... }

创建具有生命周期的组件

在这一步,创建一个组件去响应生命周期拥有者Activity。在Fragment也是类似的原则和步骤。

使用Android框架的LocationManager获取当前的经纬度,并显示给用户。你需要添加:

  • 使用LiveData订阅变化并自动更新UI
  • 创建LocationManager的包装类,基于Activity状态的变化注册和取消注册。

通常在Activity的onStart()或者onResume()方法设置LocationManager的监听,在onStop()onPause()方法取消监听:

    // Typical use, within an activity.

    @Override
    protected void onResume() {
    mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mListener);
    }

    @Override
    protected void onPause() {
        mLocationManager.removeUpdates(mListener);
    }

这一步,在BoundLocationManager类中使用一个LifecycleOwner的实现类LifecycleRegistryOwner。这个Boundlocationmanager类的名称是指类的实例绑定到Activity的生命周期。

为了使类可以观察Activity的生命周期,你需要把他添加到观察者。为了到达这个目标,在的构造函数添加以下的代码,使Boundlocationmanager对象可以观察生命周期:

    lifecycleOwner.getLifecycle().addObserver(this);

为了当生命周期变化时回调方法,可以使用@OnLifecycleEvent注解。在BoundLocationListener类中用下面的注解更新addLocationListener()removeLocationListener()方法。

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    void addLocationListener() {
        ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    void removeLocationListener() {
        ...
    }

注意:观察者会被带到提供者当前的状态,所以不需要在构造函数调用addLocationListener()。当你把观察者添加到生命周期拥有者时,它默认会回调。

运行APP,验证当你旋转设备时,Log Monitor是否显示下面的行为

D/BoundLocationMgr: Listener added
D/BoundLocationMgr: Listener removed
D/BoundLocationMgr: Listener added
D/BoundLocationMgr: Listener removed

使用Android模拟器,模拟设备位置的变化(点击那个三点的图标去显示更多的控制)。当位置变化时,TextView会跟着更新。

Step5 - 在Fragment之间共享ViewModel

使用ViewModel完成接下来增加的步骤,使Fragment或者下面例子的之间可以通信:

  • 单独的Activity。
  • Fragment的两个实例,这个Fragment显示SeekBar。
  • LiveData变量的ViewModel

运行这一步,注意两个SeekBar实例是相互独立的。

ViewModel连接这些Fragment,所以当一个SeekBar变化时,另一个SeekBar也更新:

注意:你应该使用Activity作为生命周期拥有者,每个Fragment的生命周期是独立的。

这里没有手把手的指导操作,但你可以在step5_solution包中找到解决方案。

猜你喜欢

转载自blog.csdn.net/zhanhong39/article/details/77284440