前言:
这是一篇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 的生命周期上。
原文:
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 ViewModel
using 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。
原文:
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。
原文:
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 示例应用查看。