[翻譯]ViewModel 概述( ViewModel Overview)

前言:

這是一篇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 的生命周期上。

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.

譯文:

通常在系統(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 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.

譯文:

這種方法提供了下面的優(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通惫。

viewmodel-loader.png

原文:

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悔政。

viewmodel-replace-loader.png

原文:

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)用查看逢勾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末牡整,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子溺拱,更是在濱河造成了極大的恐慌逃贝,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迫摔,死亡現(xiàn)場離奇詭異沐扳,居然都是意外死亡,警方通過查閱死者的電腦和手機句占,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門沪摄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纱烘,你說我怎么就攤上這事杨拐。” “怎么了擂啥?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵哄陶,是天一觀的道長。 經(jīng)常有香客問我哺壶,道長屋吨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任山宾,我火速辦了婚禮至扰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘资锰。我一直安慰自己渊胸,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布台妆。 她就那樣靜靜地躺著翎猛,像睡著了一般胖翰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上切厘,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天萨咳,我揣著相機與錄音,去河邊找鬼疫稿。 笑死培他,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的遗座。 我是一名探鬼主播舀凛,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼途蒋!你這毒婦竟也來了猛遍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤号坡,失蹤者是張志新(化名)和其女友劉穎懊烤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宽堆,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡腌紧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了畜隶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片壁肋。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖籽慢,靈堂內(nèi)的尸體忽然破棺而出墩划,到底是詐尸還是另有隱情,我是刑警寧澤嗡综,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布乙帮,位于F島的核電站,受9級特大地震影響极景,放射性物質(zhì)發(fā)生泄漏察净。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一盼樟、第九天 我趴在偏房一處隱蔽的房頂上張望氢卡。 院中可真熱鬧,春花似錦晨缴、人聲如沸译秦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽筑悴。三九已至们拙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間阁吝,已是汗流浹背砚婆。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留突勇,地道東北人装盯。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像甲馋,于是被迫代替她去往敵國和親埂奈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容