Google官方架构组件 Lifecycle 和 LiveData

前言

在 Google 2017 年的 IO 大会上面发布了一些可以帮助开发人员创建更容易维护和更强大的应用程序,Lifecycle 就是其中的一个,它可以帮助我们更好的处理 Android 组件和声明周期相关的问题。

Lifecycle

Lifecycle 是一个类,它持有关于组件(如 Activity 或 Fragment)生命周期状态的信息,并且允许其他对象观察此状态。

引入 Lifecycle 扩展库

implements "android.arch.lifecycle:runtime:${architectureComponentsVersion}"
implements "android.arch.lifecycle:extensions:${architectureComponentsVersion}"

继承 LifecycleObserver 来实现声明周期观察者接口。

public interface IPresenter extends LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    void onCreate(@NotNull LifecycleOwner owner);

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy(@NotNull LifecycleOwner owner);

    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    void onLifecycleChanged(@NotNull LifecycleOwner owner,
                            @NotNull Lifecycle.Event event);
}

重写对应的 onCreateonDestroy 方法实现具体的声明周期内逻辑。

public class BasePresenter implements IPresenter {
        
    private static final String TAG = "com.qingmei2.module.base.BasePresenter";    

    @Override
    public void onLifecycleChanged(@NotNull LifecycleOwner owner, @NotNull Lifecycle.Event event) {

    }

    @Override
    public void onCreate(@NotNull LifecycleOwner owner) {
        Log.d("tag", "BasePresenter.onCreate" + this.getClass().toString());
    }

    @Override
    public void onDestroy(@NotNull LifecycleOwner owner) {
        Log.d("tag", "BasePresenter.onDestroy" + this.getClass().toString());
    }
}

在 Activity 和 Fragment 容器中添加 Observer,注册具体的观者对象。

public class MainActivity extends AppCompatActivity {
    private IPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("tag", "onCreate" + this.getClass().toString());
        setContentView(R.layout.activity_main);
        mPresenter = new MainPresenter(this);
        //添加LifecycleObserver
        getLifecycle().addObserver(mPresenter);
    }

    @Override
    protected void onDestroy() {
        Log.d("tag", "onDestroy" + this.getClass().toString());
        super.onDestroy();
    }
}

如此,每当 Activity 发生了对应的生命周期改变,Presenter 就会执行对应事件注解的方法。除 onCreate 和 onDestroy 事件之外,Lifecycle 一共提供了所有的生命周期事件,只要通过注解进行声明,就能够使 LifecycleObserver 观察到对应的生命周期事件。

 public enum Event {
    /**
        * Constant for onCreate event of the {@link LifecycleOwner}.
        */
    ON_CREATE,
    /**
        * Constant for onStart event of the {@link LifecycleOwner}.
        */
    ON_START,
    /**
        * Constant for onResume event of the {@link LifecycleOwner}.
        */
    ON_RESUME,
    /**
        * Constant for onPause event of the {@link LifecycleOwner}.
        */
    ON_PAUSE,
    /**
        * Constant for onStop event of the {@link LifecycleOwner}.
        */
    ON_STOP,
    /**
        * Constant for onDestroy event of the {@link LifecycleOwner}.
        */
    ON_DESTROY,
    /**
        * An {@link Event Event} constant that can be used to match all events.
        */
    ON_ANY
}

例如这样:

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void unregisterObserver() {
    lifecycle.removeObserver(this);
}

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void sendDummyLocation() {
    locationListener.updateLocation(LOCATION);
}

以 Fragment 为例,Activity 是类似的,类的结构关系如下:

Lifecycle类的结构关系

LifecycleObserver接口( Lifecycle 观察者):实现该接口的类,通过注解的方式,可以通过被 LifecycleOwner 类的 addObserver(LifecycleObserver o) 方法注册,被注册后,LifecycleObserver 便可以观察到 LifecycleOwner 的生命周期事件。

LifecycleOwner接口(Lifecycle 持有者):实现该接口的类持有生命周期( Lifecycle 对象),该接口的生命周期( Lifecycle 对象)的改变会被其注册的观察者 LifecycleObserver 观察到并触发其对应的事件。

Lifecycle(生命周期):和 LifecycleOwner 不同的是,LifecycleOwner 本身持有 Lifecycle 对象,LifecycleOwner 通过其 Lifecycle getLifecycle() 的接口获取内部 Lifecycle 对象。

State(当前生命周期所处状态):如图所示。

Event(当前生命周期改变对应的事件):如图所示,当 Lifecycle 发生改变,如进入 onCreate, 会自动发出 ON_CREATE 事件。

Fragment (Activity同理) 实现了 LifecycleOwner 接口,这意味着 Fragment 对象持有生命周期对象(Lifecycle),并可以通过 Lifecycle getLifecycle() 方法获取内部的 Lifecycle 对象:

public class Fragment implements xxx, LifecycleOwner {
    
    //...省略其他

   LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
}

public interface LifecycleOwner {
    @NonNull
    Lifecycle getLifecycle();
}

LifecycleRegistry 本身就是一个成熟的 Lifecycle 实现类,它被实例化在 Activity 和 Fragment 中使用,如果我们需要自定义 LifecycleOwner 并实现接口需要返回一个 Lifecycle 实例,完全可以直接在自定义 LifecycleOwner 中 new 一个 LifecycleRegistry 成员并返回它(简而言之就是:直接拿来用即可)。其次,Google 的 Lifecycle 库中提供了一个 DefaultLifecycleObserver 类,方便我们直接实现 LifecycleObserver 接口,相比较于文中demo所使用的注解方式,Google 官方更推荐我们使用 DefaultLifecycleObserver 类。

LiveData

对于用过 RxJava 的朋友可能会对这个 LiveData 感到熟悉,它们所做的事情大致一样。LiveData 可以由感兴趣的一放订阅,在每次数据发生变化的时候通知订阅方,和 RxJava 不同的是它可以感知并遵循 Activity、Fragment 或Service 等组件的生命周期。正是由于 LiveData 对组件生命周期可感知特点,因此可以做到仅在组件处于生命周期的激活状态时才更新 UI 数据。

LiveData 需要一个观察者对象,一般是 Observer 类的具体实现。当观察者的生命周期处于 STARTED 或 RESUMED 状态时,LiveData 会通知观察者数据变化;在观察者处于其他状态时,即使 LiveData 的数据变化了,也不会通知。

LiveData 可以使用如下方法注册观察者:

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {}

第一个参数为 LifecycleOwner,在新的兼容库中,Activity、Fragment 等都实现了 LifecycleOwner 接口。 LifecycleOwner 可以获取 Lifecycle,从而得到组件的各生命周期状态。

第二个参数为观察者对象,当数据源变化时就会回调。

通过 LiveData 的 observe 方法进行关系绑定,就可以在组件的生命周期状态变为 DESTROYED 时移除观察者,这样 Activity 或 Fragment 就可以安全地观察 LiveData 而不用担心造成内存泄露。

使用场景

在 ViewModel 中创建 LiveData,并持有某种类型的数据。

public class NameViewModel extends ViewModel {

// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;

    public MutableLiveData<String> getCurrentName() {
        if (mCurrentName == null) {
            mCurrentName = new MutableLiveData<String>();
        }
        return mCurrentName;
    }

// Rest of the ViewModel...
}

创建一个 Observer 对象并实现其 onChanged() 回调,一般在 Activity 或 Fragment 中创建 Observer。

在 Activity 或 Fragment 中通过 LiveData 的 observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) 方法建立观察关系。

public class NameActivity extends AppCompatActivity {

    private NameViewModel mModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Other code to setup the activity...

        // Get the ViewModel.
        mModel = ViewModelProviders.of(this).get(NameViewModel.class);

        // Create the observer which updates the UI.
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newName) {
                // Update the UI, in this case, a TextView.
                mNameTextView.setText(newName);
            }
        };

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        mModel.getCurrentName().observe(this, nameObserver);
    }
}

LiveData 没有对外提供公有的修改数据的方法,而其子类 MutableLiveData 提供了setValue(T) (主线程使用) 和 postValue(T)(子线程使用)两个方法允许修改数据。MutableLiveData 源码定义如下:

/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
 */
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

在前几步的基础上,我们通过一个按钮来触发修改 LiveData 数据,看对应的 UI 是否得到更新:

mButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        String anotherName = "John Doe";
        mModel.getCurrentName().setValue(anotherName);
    }
});

当触发 LiveData 的 setValue(T) 时,观察者对象的 onChanged() 被回调,从而更新 UI。

LiveData结合Room使用

Room 是 Android 官方的持久化数据库方案,支持返回 LiveData 对象,当数据库变化时会更新 LiveData,这些逻辑由 Room 自动生成。

上述逻辑是在后台异步进行的,这种模式可以使 UI 跟数据库的数据保持同步。

更多关于 Room 的用法可参考 Room persistent library guide