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í)候。

您通常在系統(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)引用較少。

在使用加載器的一種常見方法中,應(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。

余留問題
隨著數(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: 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
來源:https://developer.android.google.cn/topic/libraries/architecture/viewmodel