[翻译]ViewModel 概述( ViewModel Overview)

前言:

这是一篇Android官方关于ViewModel介绍的翻译,ViewModel 的目的是封装 UI 控制器的数据,并让数据在配置改变时存活。ViewModel 把 UI 控制器从数据加载中分离开来。也可以在 fragment 中共享数据。


原文:

ViewModel Overview

译文:

ViewModel 概述

原文:

The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.

译文:

定义 ViewModel 类是以生命周期感知的方式存储和管理 UI 相关数据。ViewModel 类使得数据在例如屏幕旋转这样的配置改变中幸存。

原文:

Note: To import ViewModel into your Android project, see adding components to your project.

译文:

注意:为了把 ViewModel 导入你的 Android 工程,查阅 添加组件到你的项目.

原文:

The Android framework manages the lifecycles of UI controllers, such as activities and fragments. The framework may decide to destroy or re-create a UI controller in response to certain user actions or device events that are completely out of your control.

译文:

Android framework 管理 UI 控制器的生命周期,例如 activities 和 fragments,framework 可能决定销毁或者重建一个 UI 控制器,来响应用户的具体动作,或者那些完全在你控制之外的设备事件。

原文:

If the system destroys or re-creates a UI controller, any transient UI-related data you store in them is lost. For example, your app may include a list of users in one of its activities. When the activity is re-created for a configuration change, the new activity has to re-fetch the list of users. For simple data, the activity can use the [onSaveInstanceState()](https://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle))method and restore its data from the bundle in [onCreate()](https://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)), but this approach is only suitable for small amounts of data that can be serialized then deserialized, not for potentially large amounts of data like a list of users or bitmaps.

译文:

如果系统销毁或者重新创建了一个 UI 控制器,任何你存储在它们中的瞬态 UI 相关数据会丢失。例如,你的应用在它的一个 activity 中保存了一个用户列表,当 activity 因为配置改变重新创建的时候,新 Activity 不得不重新获取用户列表。对于简单数据,activity 可以使用 onSaveInstanceState() 方法并且在 onCreate() 中从 bundle 还原它的值。但是这种方法只适合少量的可序列化/反序列化数据,不适合潜在的大量数据例如一个用户列表或者位图。

原文:

Another problem is that UI controllers frequently need to make asynchronous calls that may take some time to return. The UI controller needs to manage these calls and ensure the system cleans them up after it's destroyed to avoid potential memory leaks. This management requires a lot of maintenance, and in the case where the object is re-created for a configuration change, it's a waste of resources since the object may have to reissue calls it has already made.

译文:

另一个问题是 UI 控制器需要频繁地创建异步调用,这会耗费一些时间。UI 控制器需要管理这些调用,并且确保系统在它销毁时清理它们,避免潜在的内存泄露。这项管理需要许多维护,而且在配置改变时重新创建对象,这是一种资源浪费,由于这些对象不得不重复它们已经做过的调用。

原文:

UI controllers such as activities and fragments are primarily intended to display UI data, react to user actions, or handle operating system communication, such as permission requests. Requiring UI controllers to also be responsible for loading data from a database or network adds bloat to the class. Assigning excessive responsibility to UI controllers can result in a single class that tries to handle all of an app's work by itself, instead of delegating work to other classes. Assigning excessive responsibility to the UI controllers in this way also makes testing a lot harder.

译文:

像 activities 和 fragments 这样的 UI 控制器的主要意图是显示 UI 数据,响应用户行为,或者处理操作系统通信,例如权限申请。要求 UI 控制器同时负责从数据库或者网络加载数据使类变得臃肿。给 UI 控制器分配过度的职责会导致一个类在尝试自己处理应用的所有工作,而不是把工作委托给其他类。给 UI 控制器分配过度的职责使得难以测试。

原文:

It's easier and more efficient to separate out view data ownership from UI controller logic.

译文:

把视图数据拥有关系从 UI 控制逻辑分离开来很容易并且更有效。

原文:

Implement a ViewModel

Architecture Components provides ViewModel helper class for the UI controller that is responsible for preparing data for the UI. ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. For example, if you need to display a list of users in your app, make sure to assign responsibility to acquire and keep the list of users to a ViewModel, instead of an activity or fragment, as illustrated by the following sample code:

译文:

实现一个 ViewModel

架构组件给 UI 控制器提供 ViewModel 辅助类,它负责给 UI 准备数据。ViewModel 对象在配置改变时被自动保留,因此,它们保存的数据对下一个 activity 或 fragment 实例立即可用。例如,你需要在你的应用中展示一个用户列表,确保把获取和保存用户列表的职责分配给一个 ViewModel,而不是一个 activity 或 fragment,像下面的示例代码说明的一样:

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

原文:

You can then access the list from an activity as follows:

译文:

然后你可以在一个 activity 中像下面一样访问列表:

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

原文:

If the activity is re-created, it receives the same MyViewModel instance that was created by the first activity. When the owner activity is finished, the framework calls the ViewModel objects's onCleared() method so that it can clean up resources.

译文:

如果 activity 被重新创建,它接收与第一个 activity 创建的相同 MyViewModel 实例。当所有者 activity 关闭时,framework 调用 ViewModel 对象的 onCleared() 方法,所以它能清理资源。

原文:

Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.

译文:

注意:ViewModel 决不能引用一个 view,Lifecycle 或者任何持有 activity context 引用的类。

原文:

ViewModel objects are designed to outlive specific instantiations of views or LifecycleOwners. This design also means you can write tests to cover a ViewModel more easily as it doesn't know about view and Lifecycle objects.

译文:

ViewModel 对象被设计成比 views 或 LifecycleOwners 的特定实例存活更久。这样设计意味着你可以更容易编写覆盖一个 ViewModel 的测试,由于它不知道 view 和 Lifecycle 对象。

原文:

ViewModel objects can contain LifecycleObservers, such as LiveData objects. However ViewModel objects must never observe changes to lifecycle-aware observables, such as LiveData objects. If the ViewModel needs the[Application](https://developer.android.com/reference/android/app/Application.html) context, for example to find a system service, it can extend the AndroidViewModel class and have a constructor that receives the [Application](https://developer.android.com/reference/android/app/Application.html) in the constructor, since [Application](https://developer.android.com/reference/android/app/Application.html) class extends [Context](https://developer.android.com/reference/android/content/Context.html).

译文:

ViewModel 对象可以包含 LifecycleObservers,例如 LiveData 对象。然而 ViewModel 对象决不能观察 lifecycle-aware observables (生命周期感知可观察) 的改变,例如 LiveData 对象。如果 ViewModel 需要 Application 的 context,例如寻找系统服务,它可以扩展 AndroidViewModel 类,有一个构造器接收 Application,因为 Application 继承了 Context。

原文:

The lifecycle of a ViewModel

ViewModel objects are scoped to the Lifecycle passed to the ViewModelProvider when getting the ViewModel. The ViewModel remains in memory until the Lifecycle it's scoped to goes away permanently: in the case of an activity, when it finishes, while in the case of a fragment, when it's detached.

译文:

ViewModel 的生命周期

ViewModel 对象在获取 ViewModel 时,作用范围是传递给 ViewModelProvider 的 Lifecycle ,ViewModel保留在内存,直到作用范围永远消失。如果是一个 activity,当它 finishe 的时候,如果是一个 fragment,当它 detach 的时候。

原文:

Figure 1 illustrates the various lifecycle states of an activity as it undergoes a rotation and then is finished. The illustration also shows the lifetime of the ViewModel next to the associated activity lifecycle. This particular diagram illustrates the states of an activity. The same basic states apply to the lifecycle of a fragment.

译文:

图 1 说明了一个 activity 的多种生命周期状态,当它经历一个轮回然后结束。这个图还展示了紧挨着关联 activity 生命周期的 ViewModel 的一生,这个具体的图说明了 activity 的状态,相同的基础状态应用到了 fragment 的生命周期上。

viewmodel-lifecycle.png

原文:

You usually request a ViewModel the first time the system calls an activity object's [onCreate()](https://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)) method. The system may call [onCreate()](https://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)) several times throughout the life of an activity, such as when a device screen is rotated. TheViewModel exists from when you first request a ViewModel until the activity is finished and destroyed.

译文:

通常在系统第一次调用 activity 对象的 onCreate() 方法时请求一个 ViewModel。系统可能在 activity 的一生中调用数次 onCreate(),例如设备屏幕旋转。ViewModel 从你第一次请求直到 activity 结束并销毁期间都存在。

原文:

Share data between fragments

It's very common that two or more fragments in an activity need to communicate with each other. Imagine a common case of master-detail fragments, where you have a fragment in which the user selects an item from a list and another fragment that displays the contents of the selected item. This case is never trivial as both fragments need to define some interface description, and the owner activity must bind the two together. In addition, both fragments must handle the scenario where the other fragment is not yet created or visible.

译文:

在 fragment 中共享数据

一个 activity 中的两个或多个 fragment 相互通信是非常见的。想象一个普遍的情景,master-detail fragment,有一个 fragment,用户选择它里面的列表的一个条目,另一个 fragment 显示选中条目的内容。这种情景并不是微不足道的,因为两个 fragment 需要定义一些接口描述,并且所属 activity 必须同时绑定它们两个。另外,两个 fragment 必须处理另一个还没有创建或者不可见的场景。

原文:

This common pain point can be addressed by using ViewModel objects. These fragments can share a ViewModelusing their activity scope to handle this communication, as illustrated by the following sample code:

译文:

这个普遍的痛点可以用 ViewModel 对象解决,这些 fragment 可以共享同一个 ViewModel,用它们的 activity 作用域处理这些通信,像下面的示例代码展示的一样:

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}


public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, item -> {
           // Update the UI.
        });
    }
}

原文:

Notice that both fragments use [getActivity()](https://developer.android.com/reference/android/app/Fragment.html#getActivity()) when getting the ViewModelProvider. As a result, both fragments receive the same SharedViewModel instance, which is scoped to the activity.

译文:

注意两个 fragment 在获取 ViewModelProvider 时使用 getActivity()。最终,两个 fragment 收到同一个作用在 activity 上 SharedViewModel 实例。

原文:

This approach offers the following benefits:

The activity does not need to do anything, or know anything about this communication.
Fragments don't need to know about each other besides the SharedViewModel contract. If one of the fragments disappears, the other one keeps working as usual.
Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one. If one fragment replaces the other one, the UI continues to work without any problems.

译文:

这种方法提供了下面的优势:

activity 不需要做任何事情,或知道任何和这个通信相关的事情。
Fragment 不需要相互知道,除了 SharedViewModel 合约。如果一个 fragment 不在了,另一个还能正常工作。
每一个 fragment 有它自己的生命周期,不受另一个生命周期的影响,如果一个 fragment 替换了另一个,UI 继续工作,没有任何问题。

原文:

Replacing Loaders with ViewModel

Loader classes like [CursorLoader](https://developer.android.com/reference/android/content/CursorLoader.html) are frequently used to keep the data in an app's UI in sync with a database. You can use ViewModel, with a few other classes, to replace the loader. Using a ViewModel separates your UI controller from the data-loading operation, which means you have fewer strong references between classes.

译文:

用 ViewModel 替代 Loaders

Loader 类比如 CursorLoader 被频繁地用来同步应用 UI 和数据库之间的数据。你可以使用 ViewModel,和少许其它类,代替 loader。使用一个 ViewModel 把你的 UI 控制器从数据加载中分离开来,这意味着类之间有更少的强引用。

原文:

In one common approach to using loaders, an app might use a [CursorLoader](https://developer.android.com/reference/android/content/CursorLoader.html) to observe the contents of a database. When a value in the database changes, the loader automatically triggers a reload of the data and updates the UI:

译文:

使用 loaders 的一个通用方式是,一个应用可能使用一个 CursorLoader 来观察数据库内容。当数据库中的一个值改变时,loader 自动触发一个数据加载并更新 UI。

viewmodel-loader.png

原文:

Figure 2. Loading data with loaders

译文:

图2. 用 loaders 加载数据

原文:

ViewModel works with Room and LiveData to replace the loader. The ViewModel ensures that the data survives a device configuration change. Room informs your LiveData when the database changes, and the LiveData, in turn, updates your UI with the revised data.

译文:

ViewModel, Room 和 LiveData 一起来替换 loader,ViewModel 确保数据在设备配置改变时存活。当数据库变化时,Room 通知你的 LiveData,然后 LiveData 反过来,用已修改的数据更新 UI。

viewmodel-replace-loader.png

原文:

Figure 3. Loading data with ViewModel

译文:

图3. 用 ViewModel 加载数据

原文:

Additional resources

This blog post describes how to use a ViewModel with a LiveData to replace an [AsyncTaskLoader](https://developer.android.com/reference/android/content/AsyncTaskLoader.html).

译文:

附加资源

这篇博客 介绍如何使用一个 ViewModel 和一个 LiveData 代替一个 AsyncTaskLoader。

原文:

As your data grows more complex, you might choose to have a separate class just to load the data. The purpose ofViewModel is to encapsulate the data for a UI controller to let the data survive configuration changes. For information about how to load, persist, and manage data across configuration changes, see Saving UI States.

译文:

如果你的数据变得更加复杂,你可能选择一个分离的类仅仅加载数据。ViewModel 的目的是封装 UI 控制器的数据,并让数据在配置改变时存活。关于如何在配置改变中加载,持久化和管理数据,查看保存 UI 状态

原文:

The Guide to Android App Architecture suggests building a repository class to handle these functions.

译文:

Android 应用架构指南 建议创建一个 repository 类处理这些功能。

原文:

ViewModel is an Android Jetpack architecture component. See it in use in the Sunflower demo app.

译文:

ViewModel 是一个 Android Jetpack 架构组件,使用 Sunflower 示例应用查看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容