前言:
這是一篇Android官方關(guān)于ViewModel介紹的翻譯墓赴,ViewModel 的目的是封裝 UI 控制器的數(shù)據(jù)泳赋,并讓數(shù)據(jù)在配置改變時存活净宵。ViewModel 把 UI 控制器從數(shù)據(jù)加載中分離開來腕让。也可以在 fragment 中共享數(shù)據(jù)。
原文:
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 相關(guān)數(shù)據(jù)。ViewModel 類使得數(shù)據(jù)在例如屏幕旋轉(zhuǎn)這樣的配置改變中幸存。
原文:
Note: To import
ViewModel
into your Android project, see adding components to your project.
譯文:
注意:為了把 ViewModel 導(dǎo)入你的 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 控制器帜篇,來響應(yīng)用戶的具體動作惯雳,或者那些完全在你控制之外的設(shè)備事件队橙。
原文:
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.
譯文:
如果系統(tǒng)銷毀或者重新創(chuàng)建了一個 UI 控制器拦坠,任何你存儲在它們中的瞬態(tài) UI 相關(guān)數(shù)據(jù)會丟失连躏。例如,你的應(yīng)用在它的一個 activity 中保存了一個用戶列表贞滨,當(dāng) activity 因為配置改變重新創(chuàng)建的時候入热,新 Activity 不得不重新獲取用戶列表。對于簡單數(shù)據(jù)晓铆,activity 可以使用 onSaveInstanceState() 方法并且在 onCreate() 中從 bundle 還原它的值勺良。但是這種方法只適合少量的可序列化/反序列化數(shù)據(jù),不適合潛在的大量數(shù)據(jù)例如一個用戶列表或者位圖尤蒿。
原文:
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 控制器需要頻繁地創(chuàng)建異步調(diào)用郑气,這會耗費一些時間。UI 控制器需要管理這些調(diào)用腰池,并且確保系統(tǒng)在它銷毀時清理它們尾组,避免潛在的內(nèi)存泄露。這項管理需要許多維護(hù)示弓,而且在配置改變時重新創(chuàng)建對象讳侨,這是一種資源浪費,由于這些對象不得不重復(fù)它們已經(jīng)做過的調(diào)用奏属。
原文:
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 數(shù)據(jù)跨跨,響應(yīng)用戶行為,或者處理操作系統(tǒng)通信囱皿,例如權(quán)限申請勇婴。要求 UI 控制器同時負(fù)責(zé)從數(shù)據(jù)庫或者網(wǎng)絡(luò)加載數(shù)據(jù)使類變得臃腫。給 UI 控制器分配過度的職責(zé)會導(dǎo)致一個類在嘗試自己處理應(yīng)用的所有工作嘱腥,而不是把工作委托給其他類耕渴。給 UI 控制器分配過度的職責(zé)使得難以測試。
原文:
It's easier and more efficient to separate out view data ownership from UI controller logic.
譯文:
把視圖數(shù)據(jù)擁有關(guān)系從 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:
譯文:
實現(xiàn)一個 ViewModel
架構(gòu)組件給 UI 控制器提供 ViewModel 輔助類橱脸,它負(fù)責(zé)給 UI 準(zhǔn)備數(shù)據(jù)。ViewModel 對象在配置改變時被自動保留分苇,因此添诉,它們保存的數(shù)據(jù)對下一個 activity 或 fragment 實例立即可用。例如医寿,你需要在你的應(yīng)用中展示一個用戶列表栏赴,確保把獲取和保存用戶列表的職責(zé)分配給一個 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 被重新創(chuàng)建须眷,它接收與第一個 activity 創(chuàng)建的相同 MyViewModel 實例乌叶。當(dāng)所有者 activity 關(guān)閉時,framework 調(diào)用 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 對象被設(shè)計成比 views 或 LifecycleOwners 的特定實例存活更久。這樣設(shè)計意味著你可以更容易編寫覆蓋一個 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涵亏,例如尋找系統(tǒng)服務(wù)宰睡,它可以擴展 AndroidViewModel 類,有一個構(gòu)造器接收 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保留在內(nèi)存麸恍,直到作用范圍永遠(yuǎn)消失。如果是一個 activity搀矫,當(dāng)它 finishe 的時候抹沪,如果是一個 fragment,當(dāng)它 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 的多種生命周期狀態(tài)融欧,當(dāng)它經(jīng)歷一個輪回然后結(jié)束。這個圖還展示了緊挨著關(guān)聯(lián) activity 生命周期的 ViewModel 的一生冰垄,這個具體的圖說明了 activity 的狀態(tài)蹬癌,相同的基礎(chǔ)狀態(tài)應(yīng)用到了 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.
譯文:
通常在系統(tǒng)第一次調(diào)用 activity 對象的 onCreate() 方法時請求一個 ViewModel虹茶。系統(tǒng)可能在 activity 的一生中調(diào)用數(shù)次 onCreate()逝薪,例如設(shè)備屏幕旋轉(zhuǎn)。ViewModel 從你第一次請求直到 activity 結(jié)束并銷毀期間都存在蝴罪。
原文:
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 中共享數(shù)據(jù)
一個 activity 中的兩個或多個 fragment 相互通信是非常見的董济。想象一個普遍的情景,master-detail fragment要门,有一個 fragment虏肾,用戶選擇它里面的列表的一個條目廓啊,另一個 fragment 顯示選中條目的內(nèi)容。這種情景并不是微不足道的封豪,因為兩個 fragment 需要定義一些接口描述谴轮,并且所屬 activity 必須同時綁定它們兩個。另外吹埠,兩個 fragment 必須處理另一個還沒有創(chuàng)建或者不可見的場景第步。
原文:
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.
譯文:
這種方法提供了下面的優(yōu)勢:
activity 不需要做任何事情,或知道任何和這個通信相關(guān)的事情呻纹。
Fragment 不需要相互知道堆生,除了 SharedViewModel 合約。如果一個 fragment 不在了雷酪,另一個還能正常工作顽频。
每一個 fragment 有它自己的生命周期,不受另一個生命周期的影響太闺,如果一個 fragment 替換了另一個糯景,UI 繼續(xù)工作,沒有任何問題省骂。
原文:
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 被頻繁地用來同步應(yīng)用 UI 和數(shù)據(jù)庫之間的數(shù)據(jù)蟀淮。你可以使用 ViewModel,和少許其它類钞澳,代替 loader怠惶。使用一個 ViewModel 把你的 UI 控制器從數(shù)據(jù)加載中分離開來,這意味著類之間有更少的強引用轧粟。
原文:
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 的一個通用方式是策治,一個應(yīng)用可能使用一個 CursorLoader 來觀察數(shù)據(jù)庫內(nèi)容。當(dāng)數(shù)據(jù)庫中的一個值改變時兰吟,loader 自動觸發(fā)一個數(shù)據(jù)加載并更新 UI通惫。
原文:
Figure 2. Loading data with loaders
譯文:
圖2. 用 loaders 加載數(shù)據(jù)
原文:
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 確保數(shù)據(jù)在設(shè)備配置改變時存活履腋。當(dāng)數(shù)據(jù)庫變化時,Room 通知你的 LiveData,然后 LiveData 反過來遵湖,用已修改的數(shù)據(jù)更新 UI悔政。
原文:
Figure 3. Loading data with ViewModel
譯文:
圖3. 用 ViewModel 加載數(shù)據(jù)
原文:
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.
譯文:
如果你的數(shù)據(jù)變得更加復(fù)雜延旧,你可能選擇一個分離的類僅僅加載數(shù)據(jù)谋国。ViewModel 的目的是封裝 UI 控制器的數(shù)據(jù),并讓數(shù)據(jù)在配置改變時存活迁沫。關(guān)于如何在配置改變中加載烹卒,持久化和管理數(shù)據(jù),查看保存 UI 狀態(tài)
原文:
The Guide to Android App Architecture suggests building a repository class to handle these functions.
譯文:
Android 應(yīng)用架構(gòu)指南 建議創(chuàng)建一個 repository 類處理這些功能弯洗。
原文:
ViewModel
is an Android Jetpack architecture component. See it in use in the Sunflower demo app.
譯文:
ViewModel 是一個 Android Jetpack 架構(gòu)組件,使用 Sunflower 示例應(yīng)用查看逢勾。