Android深入学习之观察者模式与ViewModel的实现机制

发布时间 2023-11-10 23:00:05作者: 南风小斯

1.观察者模式 Observer Pattern

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

定义对象间的一种一对多依赖关系,当该对象(subject)改变状态时,所有依赖于它的对象(observers)都会得到通知并被自动更新。

通常在被观察的类Subject中会定义addObserver()添加观察者、removeObserver()删除观察者、notify()通知观察者三个方法;在观察者类Observer中会定义update()更新方法,即观察到Subject类的变化后,要做哪些操作。

 

2.Android中具有生命周期的类

先来看下ComponentActivity类的定义。

可见它实现了LifecycleOwner接口。根据官方文档的描述,该接口用于标识一个类具有生命周期。该接口中定义了getLifecycle()方法,其返回值类型为Lifecycle类。

Lifecycle类中定义了两个枚举Event和State,此外还定义有addObserver(LifecycleObserver)和removeObserver(LifecycleObserver)两个方法。可见,Lifecycle类扮演着观察者模式中的Subject角色,它存储类的生命周期状态信息,使用Event和State跟踪其生命周期状态,并允许该类被其他类观察。

对于Activity类而言,其生命周期中有6个核心回调方法,Event和State对应关系如下图所示。

举个例子,当MainActivity的onCreate()被调用时,与MainActivity关联的Lifecycle对象就会发出ON_CREATE事件,同时标记MainActivity当前的状态为CREATED。相应地,通过addObserver()添加的LifecycleObserver可以接收到ON_CREATE事件,同时知道MainActivity当前是CREATED状态。

LifecycleObserver是个标识接口,LifecycleEventObserver是其一个子接口,其中定义的onStateChanged(LifecyclerOwner, Lifecycle.Event)方法其实就是Observer中的update()方法。

用代码来举例,新建一个类MainObserver,实现LifecycleEventObserver接口,用来观察MainActivity类的生命周期状态。

public class MainObserver implements LifecycleEventObserver {
    public static final String TAG="MainObserver";
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
        // 先获取到MainActivity中的Lifecycle类型变量
        Lifecycle lifecycle=source.getLifecycle();
        if(lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED))
            Log.d(TAG,String.format("observe that the current state of %s is STARTED at %s",source,new Date()));

        if(event.equals(Lifecycle.Event.ON_PAUSE))
            Log.d(TAG,String.format("receive %s from %s",event,source));
    }
}

日志输出如下图所示。

PS:通过源代码可发现,在ComponentActivity中重写的getLifecycle()方法其实是变量mLifecycleRegistry相应的getter方法,而该变量其实是LifecycleRegistry类型,这个类是抽象类Lifecycle的一个子类。但这里并不打算对该类进行详细说明。

 

3.Android中的ViewModel

ViewModel可用来存储数据,因为它的实例存在的时间会长于Activity的生命周期。即便是配置发生更改,旧的Activity实例被销毁,新的Activity实例被创建的过程中,ViewModel的实例始终存在。那么ViewModel是如何实现的呢。

首先在Activity中使用ViewModel时,不能直接new出来一个对象,这样的话完全起不到在配置更改时保存数据的作用。取而代之的是用ViewModelProvider类来获取一个ViewModel对象。例如已经写好了一个MainViewModel用来保存MainActivity类中的数据,那么在MainActivity中获取其实例的方法可以是:

MainViewModel viewModel=new ViewModelProvider(this).get(MainViewModel.class);

那么就先从ViewModelProvider类的源代码开始看起。在我的SDK版本中,这个类是用kotlin实现的,虽然我没学过kotlin,但是也能差不多看懂吧。其中一个构造函数用JAVA写为:

public ViewModelProvider(ViewModelStoreOwner viewModelStoreOwner){}

ViewModelStoreOwner是一个单一方法接口,其中定义getViewModelStore()方法,返回ViewModelStore类型。再来看下ComponentActivity类的代码,可以看到ComponentActivity实现了ViewModelStoreOwner接口,并且其中重写的getViewModelStore()方法实际就是ComponentActivity类中定义的ViewModelStore类型的私有变量。

下面再来看看ViewModelStore类是啥。源代码如下。

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
     // 如果字典中已有该key,则更新字典,并返回旧的ViewModel实例   ViewModel oldViewModel
= mMap.put(key, viewModel);
    // 如果旧的ViewModel实例不为空,则清除它
if (oldViewModel != null) { oldViewModel.onCleared(); } } final ViewModel get(String key) { return mMap.get(key); } Set<String> keys() { return new HashSet<>(mMap.keySet()); } /** * Clears internal storage and notifies ViewModels that they are no longer used. */ public final void clear() { for (ViewModel vm : mMap.values()) { vm.clear(); } mMap.clear(); } }

可以发现,ViewModelStore类的作用就是用字典存ViewModel实例。在ViewModelProvider类中,它会获取构造函数输入的ViewModelStoreOwner类的ViewModelStore变量。调用ViewModelProvider.get(ViewModel)方法时,则先从ViewModelStore字典中查找是否有ViewModel实例,如果没有的话,再用factory创建ViewModel实例并put到字典中。

接下来看看配置发生变化时,会怎么样。在ComponentActivity的构造函数中有如下代码

public ComponentActivity() {
        Lifecycle lifecycle = getLifecycle();
        ...
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // Clear out the available context
                    mContextAwareHelper.clearAvailableContext();
                    // And clear the ViewModelStore
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });

      ...
      
    }

可见,有个LifecycleEventObserver对象在观察Activity的生命周期状态,当接收到MainActivity发出的ON_DESTROY事件时,会根据是否为配置发生更改而选择是否要clear掉ViewModelStore。

 

Refs.

[1] 设计模式之禅

[2] Android官方文档+源代码