ViewModel簡介

ViewModel概述

ViewModel類旨在以生命周期意識的方式存儲和管理與UI相關(guān)的數(shù)據(jù)。ViewModel類允許數(shù)據(jù)在配置更改(例如屏幕旋轉(zhuǎn))后繼續(xù)存在。

使用ViewModel的原因

Android framework 管理UI控制器的生命周期,例如Activities和Fragments。UI controllers 包括?activities and fragments 。

如果系統(tǒng)銷毀或重新創(chuàng)建UI控制器,則存儲在其中的任何瞬態(tài)UI相關(guān)數(shù)據(jù)都將丟失。

可以使用onSaveInstanceState()方法并從onCreate()中的包中恢復(fù)其數(shù)據(jù),但此方法僅適用于可以序列化然后反序列化的少量數(shù)據(jù)。但是不適用于潛在的大量數(shù)據(jù) 像用戶列表或位圖。

另一個問題是UI控制器經(jīng)常需要進(jìn)行可能需要一些時(shí)間才能返回的異步調(diào)用。 UI控制器需要管理這些調(diào)用并確保系統(tǒng)在銷毀后清理它們以避免潛在的內(nèi)存泄漏。 此管理需要大量維護(hù),并且在為配置更改重新創(chuàng)建對象的情況下,這會浪費(fèi)資源,因?yàn)閷ο罂赡鼙仨氈匦掳l(fā)出已經(jīng)進(jìn)行的調(diào)用。

要求UI控制器也負(fù)責(zé)從數(shù)據(jù)庫或網(wǎng)絡(luò)加載數(shù)據(jù),這會給類增加膨脹。 為UI控制器分配過多的責(zé)任可能導(dǎo)致單個類嘗試自己處理應(yīng)用程序的所有工作,而不是將工作委托給其他類。 以這種方式為UI控制器分配過多的責(zé)任也會使測試變得更加困難。

因此 我們要將 視圖數(shù)據(jù)所有權(quán)UI控制器邏輯 分離 。

ViewModel的使用

implementation ? 'android.arch.lifecycle:extensions:1.1.1'

添加擴(kuò)展,否則找不到ViewModelProviders 。

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.? ? }

}

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? ? ? ? });? ?

????????}

}


如果重新創(chuàng)建Activity,它將接收由第一個Activity創(chuàng)建的相同MyViewModel實(shí)例。 當(dāng)所有者Activity??is finished時(shí),框架調(diào)用ViewModel對象的onCleared()方法,以便它可以清理資源。

ViewModel絕不能引用View,Lifecycle 或 持有任何包含Activity context引用的類。

ViewModel對象可以包含LifecycleObservers,例如LiveData對象。 但是,ViewModel對象絕不能觀察到生命周期感知的可觀察對象(例如LiveData對象)的更改。 如果ViewModel需要Application上下文,例如查找系統(tǒng)服務(wù),它可以擴(kuò)展AndroidViewModel類并具有在構(gòu)造函數(shù)中接收Application的構(gòu)造函數(shù),因?yàn)锳pplication類擴(kuò)展了Context。

生命周期


ViewModel對象的范圍由獲取ViewModel時(shí)傳遞至ViewModelProvider的Lifecycle所決定。ViewModel始終處在內(nèi)存中,直到Lifecycle永久地離開—對于Activity來說,是當(dāng)它終止(finish)的時(shí)候,對于Fragment來說,是當(dāng)它分離(detached)的時(shí)候。

Activity和ViewModel 生命周期對比

您通常在系統(tǒng)第一次調(diào)用活動對象的onCreate()方法時(shí)請求ViewModel。 系統(tǒng)可以在活動的整個生命周期中多次調(diào)用onCreate(),例如在旋轉(zhuǎn)設(shè)備屏幕時(shí)。 ViewModel從您第一次請求ViewModel到活動完成并銷毀之時(shí)就存在。

Share data between fragments

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.? ? ? ? });? ?

????}

}


請注意,兩個Fragment都會檢索包含它們的Activity。 這樣,當(dāng)每個Fragment都獲得ViewModelProvider時(shí),它們會收到相同的SharedViewModel實(shí)例,該實(shí)例的范圍限定為此Activity。

1、Activity不需要做任何事情,也不需要了解這種溝通。

2、除了SharedViewModel契約之外,F(xiàn)ragment不需要彼此了解。 如果其中一個Fragment消失,另一個Fragment繼續(xù)照常工作。

3、每個Fragment都有自己的生命周期,不受另一個Fragment的生命周期的影響。 如果一個Fragment替換另一個Fragment,則UI繼續(xù)工作而沒有任何問題。

Replacing Loaders with ViewModel

像CursorLoader這樣的Loader類經(jīng)常用于保持應(yīng)用程序UI中的數(shù)據(jù)與數(shù)據(jù)庫同步。 您可以使用ViewModel和其他一些類來替換加載器。 使用ViewModel將UI控制器與數(shù)據(jù)加載操作分開,這意味著類之間的強(qiáng)引用較少。

loader.png

在使用加載器的一種常見方法中,應(yīng)用程序可能使用CursorLoader來觀察數(shù)據(jù)庫的內(nèi)容。 當(dāng)數(shù)據(jù)庫中的值發(fā)生更改時(shí),加載程序會自動觸發(fā)重新加載數(shù)據(jù)并更新UI:

ViewModel與Room和LiveData一起使用以替換加載器。 ViewModel可確保數(shù)據(jù)在設(shè)備配置更改后仍然存在。 當(dāng)數(shù)據(jù)庫發(fā)生變化時(shí),Room會通知您的LiveData,然后LiveData會使用修改后的數(shù)據(jù)更新您的UI。

ViewModel+LiveData代替Loader

余留問題

隨著數(shù)據(jù)變得越來越復(fù)雜,您可能會選擇單獨(dú)的類來加載數(shù)據(jù)。 ViewModel的目的是封裝UI控制器的數(shù)據(jù),以使數(shù)據(jù)不受配置更改的影響。 有關(guān)如何跨配置更改加載,保留和管理數(shù)據(jù)的信息,請參閱保存UI狀態(tài)。

Android App Architecture指南建議構(gòu)建一個存儲庫類來處理這些功能。

Samples

Android Architecture Components basic sample

Sunflower, a gardening app illustrating Android development best practices with Android Jetpack.

Blogs

ViewModels : A Simple Example

ViewModels: Persistence, onSaveInstanceState(), Restoring UI State and Loaders

ViewModels and LiveData: Patterns + AntiPatterns

Kotlin Demystified: Understanding Shorthand Lambda Syntax

Kotlin Demystified: Scope functions

Kotlin Demystified: When to use custom accessors

Lifecycle Aware Data Loading with Architecture Components

Videos

Android Jetpack: ViewModel


來源:https://developer.android.google.cn/topic/libraries/architecture/viewmodel

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容