伴鱼技术团队

Technology changes the world

伴鱼开放平台 上线了! 源于实践的解决方案,助力企业成就未来!

Jetpack 中 MVVM 架构实战分析

一、背景介绍

UI程序模块内部代码架构一直都是围绕着数据(Model)、逻辑(Logic)、视图(View)的分层和解耦不断发展进化。从最初的MVC到MVP,再到现在本文要讲的MVVM架构,三层结构没有发生根本变化,不同的是各层之间的交互方式及其产生的解耦程度的变化。

本文所讲主要内容是Google在Jetpack中提供的MVVM架构方案。

MVVM的基础架构图

推荐架构

  • View层负责UI展示和UI逻辑,不直接持有和操作数据。

  • 业务逻辑在ViewModel层实现,View层持有ViewModel对象,ViewModel对象持有和操作数据。View层调用ViewModel对象执行业务逻辑,读取数据进行运算并将运算结果输出到Model层。

  • Model数据的变化会触发UI的层更新,Model层通知View层通过观察者模式实现,不持有View对象。

    以上的结构设计,结合依赖倒置和观察者模式等一些设计原则和模式,可以实现各层之间的深度解耦隔离。

Google官方在Jetpack中列出了两条一般性的架构原则

  1. 关注点分离(Separation of Concerns)
  2. 数据驱动界面(Drive UI from a Model)

关注点分离是面向对象的核心概念,可以作为我们开发和架构的指导性原则。下面一张图是Google官方推荐的代码架构,在这个架构的基础上,谷歌给出了自己的MVVM架构实现方案。

推荐架构

二、Google版MVVM实现方案

  1. Lifecycle:管理Activity/Fragment的生命周期;
  2. ViewModel:以对生命周期敏感的方式,管理UI相关的数据,数据是LiveData形式;
  3. LiveData:基于观察者模式。在数据发生变化时通知UI更新或调起ViewModel层执行对应的逻辑处理。LiveData可以是对生命周期敏感的,也可以是不敏感的。

三、Google MVVM实现方案中各部分介绍

Lifecycle

上面的一张图是Jetpack中Lifecycle的类图结构。Fragment和FragmentActivity都是LifecycleOwner接口的实现类,持有一个LifecycleRegistry对象。

  • LifecycleRegistry: LifecycleRegistry继成抽象基类Lifecycle,持有一个保存有View生命周期的枚举类型State类对象。Lifecycle支持注册观察者,所有需要关心View生命周期的类和对象都可以实现LifecycleOberver接口注册为Lifecycle对象的观察者,并在对应的状态做出相应的反应。
  • LifecycleOwner: Fragment和FragmentActivity是LifecycleOwner的实现类,通过 getLifecycle() 方法对外提供当前生命周期状态。查询生命周期的对象持有的并不是一个Fragment对象或者FragmentActivity对象,而是LifecycleOwner对象,这样实现了两种对象之间的解耦。

ViewModel

  • ViewModel: 为Activity或者Fragment处理业务逻辑,准备和管理数据,也处理Activity和Fragment间的通讯。一个ViewModel被创建后有生命周期,换句话说,一个ViewModel不会因为他的宿主配置改变而被销毁。新的宿主会跟这个ViewModel重新连接。ViewModel类的目的是获得和保持Activity和Fragment需要的信息。Activity或者Fragment应该在ViewModel中能被观察状态改变。可以通过LiveData或者DataBinding实现。也可以通过自己的框架实现。ViewModel唯一的任务是管理UI的数据。ViewModel不要接触View树或者持有Activity或Fragment的引用。

  • ViewModel的管理机制。从上面的类图可以看出,ViewModel是通过ViewModelProvider和ViewModelStore进行保存和管理的。Android中FragmentActivity是ViewModelStoreOwner的实现类,提供 getViewModelStore() 方法获取所持有的ViewModelStore对象,下面贴出这个方法在FragmentActivity中的实现,看到ViewModelStore对象并不是在FragmentActivity对象中直接创建的,而是通过一个名为 FragmentActivity.NonConfigurationInstances 的类对象进行管理的,所以FragmentActivity对象持有的ViewModelStore对象是多个对象共同持有的,可以是同类型的也可以是不同了类型的,只要他们引用来自同一个 FragmentActivity.NonConfigurationInstances 对象即可。

  • ViewModelPorvider: 对象持有一个ViewModelStore对象和一个Factory对象,ViewModelStore通过HashMap存储ViewModel对象,Factory用户生成新的ViewModel对象,存入HashMap。默认ViewModelPorvider为每一个ViewModel类只能生成一个对象,在HashMap中对应的Key固定对应的。也可以通过制定不同的Key来生成多个对象。所以,在使用过程中ViewModel原则上不要直接创建,而是通过ViewModelProvider创建,尽管我们可以直接创建ViewModel对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // FragmentActivity
    @NonNull
    public ViewModelStore getViewModelStore() {
    if (this.getApplication() == null) {
    throw new IllegalStateException("Your activity is not yet attached to the Application instance. You can't request ViewModel before onCreate call.");
    } else {
    if (this.mViewModelStore == null) {
    FragmentActivity.NonConfigurationInstances nc = (FragmentActivity.NonConfigurationInstances)this.getLastNonConfigurationInstance();
    if (nc != null) {
    this.mViewModelStore = nc.viewModelStore;
    }
    if (this.mViewModelStore == null) {
    this.mViewModelStore = new ViewModelStore();
    }
    }
    return this.mViewModelStore;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // ViewModelProvider中创建ViewModel对象
    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    if (canonicalName == null) {
    throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
    }
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);
    if (modelClass.isInstance(viewModel)) {
    //noinspection unchecked
    return (T) viewModel;
    } else {
    //noinspection StatementWithEmptyBody
    if (viewModel != null) {
    // TODO: log a warning.
    }
    }

    viewModel = mFactory.create(modelClass);
    mViewModelStore.put(key, viewModel);
    //noinspection unchecked
    return (T) viewModel;
    }

LiveData

LiveData是持有数据的类,在给定的Lifecycle内被观察,同时也是生命周期的观察者。前面讲到FragmentActivity和Fragment是LifecycleOwner的实现类,需要观察他们的生命周期的类是LifecycleObserver接口的实现类。

通过LiveData提供的 observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) 方法添加观察者,观察者实现 Observer 泛型接口,并提供这个观察者相关的生命周期(LifecycleOwner)。在观察者的生命周期活跃状态时,LiveData中数据的改变都会通知观察者。

下面贴出添加观察者的observe方法源码实现,可以看到LiveData也会通过 LifecycleBoundObserver 类管理与生命周期相关的观察者,在生命周期结束后,把观察者从列表中移除,既观察者会被取消订阅。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
@NonNull final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}

public interface GenericLifecycleObserver extends LifecycleObserver {
/**
* Called when a state transition event happens.
*
* @param source The source of the event
* @param event The event
*/
void onStateChanged(LifecycleOwner source, Lifecycle.Event event);
}

向LiveData注册观察者也可以不提供LifecycleOwner,这个观察者除非显式删除,否则会一直保留在观察者列表中。注册不关注生命周期的观察者使用 observeForever(@NonNull Observer observer) 方法,实现 Observer 泛型接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
@MainThread
public void observeForever(@NonNull Observer<T> observer) {
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}

四、参考文献

Android Jetpack

欢迎关注我的其它发布渠道