Android深入学习之观察者模式与ViewModel的实现机制
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官方文档+源代码