1礁遵、概述
在I / O '17的時候轻绞,其中一個重要的主題是Architecture Components。這是一個官方的新庫榛丢。旨在幫助開發(fā)者設(shè)計“健壯铲球,可測試和可維護(hù)”的應(yīng)用程序。簡而言之晰赞,這個庫可以幫助開發(fā)者更好地處理生命周期事件和配置更改時的數(shù)據(jù)持久性稼病,同時還能幫助開發(fā)者創(chuàng)建更好的體系結(jié)構(gòu)應(yīng)用程序选侨,并避免難以維護(hù)和測試的膨脹類。
其官方文檔在這里:Android Architecture Components
這里我打算詳細(xì)討論下Architecture Components里面的Lifecycle然走、ViewModel和LiveData這3個部分援制。先看一下這三者的類和相關(guān)類的關(guān)系圖:
粗一看有些復(fù)雜,接下來會詳細(xì)分析下各個部分負(fù)責(zé)的內(nèi)容芍瑞。
2晨仑、Lifecycle
根據(jù)官方文檔,Lifecycle是一個抽象類拆檬,一個有Android 生命周期的對象附在它上面洪己, 并且它持該對象的當(dāng)前生命周期所處狀態(tài),所以其他對象可以觀察到這種狀態(tài)并做出相應(yīng)的反應(yīng)竟贯。為了跟蹤這種狀態(tài)答捕,Lifecycle類包含兩個枚舉類Event和State。
2.1 Event
一個Event代表當(dāng)Android 生命周期的對象的生命周期發(fā)生改變時候屑那,會觸發(fā)的一個生命周期事件(例如一個activity正在被恢復(fù))拱镐。在LifecycleObserver類中,可以為每個事件實現(xiàn)回調(diào)持际,這樣在生命周期的對象的生命周期改變的時候我們能進(jìn)行相關(guān)的處理沃琅。arch.lifecycle包提供了Annotation,這意味著可以在類中注釋應(yīng)該在某些生命周期事件中觸發(fā)的方法蜘欲。比如像下面這樣:
@OnLifecycleEvent(ON_STOP)
void doSometing(){
}
還可以在同一個帶注釋的方法中處理多個生命周期事件:
@OnLifecycleEvent({ON_STOP益眉,ON_START})
void doSometing(){
}
下面是各種事件的情況:
① ON_ANY:在任何生命周期事件時觸發(fā)。
② ON_CREATE:創(chuàng)建LifecycleOwner(下面會講這個類)時將觸發(fā)此事件芒填。
③ ON_DESTROY:LifecycleOwner被銷毀時將觸發(fā)此事件呜叫。
④ ON_PAUSE:LifecycleOwner暫停時將觸發(fā)此事件。
⑤ ON_RESUME:在LifecycleOwner恢復(fù)時觸發(fā)此事件殿衰。
⑥ ON_START:啟動LifecycleOwner時觸發(fā)此事件朱庆。
⑦ ON_STOP:LifecycleOwner停止時觸發(fā)此事件。
ON_CREATE闷祥,ON_START娱颊,ON_RESUME的方法會在LifeCycleOwner對應(yīng)方法(onCreate()、onStart()凯砍、onResume())返回后被調(diào)用箱硕。生命周期事件ON_DESTROY, ON_STOP, ON_PAUSE的方法會在LifeCycleOwner對應(yīng)方法(onDestory()、onStop()悟衩、onPause()被調(diào)用之前調(diào)用剧罩。
2.2 State
生命周期的State本質(zhì)上是介于兩個生命周期事件之間的一種情況。觸發(fā)事件后座泳,生命周期將進(jìn)入一個狀態(tài)惠昔,然后在觸發(fā)另一個事件時離開該狀態(tài)并進(jìn)入另一個狀態(tài)幕与。如下圖所示:
從上圖可以看到,Lifecycle實例在任意時間段里肯定是下面五個狀態(tài)的其中一種:
① INITIALISED:初始起點的生命周期狀態(tài)镇防。
② CREATED:ON_CREATE事件之后啦鸣,ON_START事件之前的狀態(tài)±囱酰或者是ON_STOP事件之后诫给,ON_DESTROY事件之前的狀態(tài)。
③ STARTED:ON_START事件之后啦扬,ON_RESUME事件之前的狀態(tài)中狂。或者是事件之ON_PAUSE后考传,ON_STOP事件之前的狀態(tài)吃型。
④ RESUMED:ON_RESUME事件之后的狀態(tài)证鸥。
⑤ DESTROYED:ON_DESTROY事件之后的狀態(tài)僚楞。
如果想獲取Lifecycle實例的當(dāng)前狀態(tài),那么可以調(diào)用getCurrentState()方法枉层,該方法允許開發(fā)者在任何時間檢索其當(dāng)前狀態(tài)泉褐。這有助于在執(zhí)行某種形式的操作之前檢查Lifecycle組件的狀態(tài)。State對象還可以調(diào)用isAtLeast()方法來判斷當(dāng)前狀態(tài)是否大于等于給定狀態(tài)鸟蜡。
2.3 Lifecycle相關(guān)方法
了解了Lifecycle所包含的State和Event枚舉類膜赃,現(xiàn)在看看Lifecycle和其它類進(jìn)行交互的一些方法。
上圖中看到可以Lifecycle的核心方法主要用來管理觀察者:
① addObserver():該方法用來添加一個Observer實例揉忘,只要LifecycleOwner改變狀態(tài)就會通知它跳座。當(dāng)添加一個Observer時,它將接收導(dǎo)致當(dāng)前狀態(tài)的所有事件泣矛。舉例來說疲眷,如果Lifecycle目前在RESUMED狀態(tài),則觀察員將收到ON_CREATE您朽,ON_START和ON_RESUME事件狂丝。
② removeObserver():可以調(diào)用此方法從Lifecycle的觀察者列表中刪除給定的觀察者。從生命周期中刪除觀察者將不再接收任何觸發(fā)事件哗总。
③ getCurrentState():返回生命周期所在的當(dāng)前狀態(tài)几颜。
前面提到了一個和Lifecycle息息相關(guān)的類LifecycleOwner,接下來看一下這個類是干什么的讯屈。
2.4 LifecycleOwner
這個其實是一個接口類蛋哭,里面只有一個方法getLifecycle()
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle();
}
里面的唯一方法getLifecycle()就是用來返回Lifecycle的。而這個方法的所代表的意思很簡單涮母,告訴要使用Lifecycle的組件谆趾,我是一個生命周期感知組件准颓,我存在生命周期的概念。我們現(xiàn)在看v4組件下的Activity棺妓,會繼承自SupportActivity攘已,和Fragment,這兩個類都實現(xiàn)了LifecycleOwner這個接口怜跑。同時這兩個類有一個LifecycleRegistry屬性样勃,這個屬性就是繼承自Lifecycle而LifecycleOwner的getLifecycle()返回的就是這個LifecycleRegistry。這樣就可以通過這個方法獲取該Activity的Lifecycle性芬,再通過對Lifecycle的觀察對Activity的生命周期進(jìn)行觀察峡眶,如下:
class MainActivity extends AppCompatActivity() {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
getLifecycle().addObserver(new SomeObserver())
}
}
SomeObserver類繼承自LifecycleObserver,如下所示
class SomeObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void MyResume() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void MyPause() {
}
}
這樣的話植锉,當(dāng)MainActivity 觸發(fā)相應(yīng)的事件辫樱,SomeObserver 就會回調(diào)相應(yīng)的方法。
到此Lifecycle相關(guān)部分介紹的差不多了,但是還不夠辉饱,官方還提供了其他已經(jīng)封裝好的能感知Lifecycle組件生命周期的配套組件LiveData和ViewModels搬男。
3 LiveData
LiveData的作用是持有一份給定的數(shù)據(jù),并且能夠在生命周期變化中觀察它彭沼。該類為開發(fā)者提供了一系列方法缔逛,方便對這個類持有數(shù)據(jù)的觀察者的管理。LiveData會根據(jù)觀察者綁定的LifecycleOwner的生命周期情況姓惑,來決定是否將數(shù)據(jù)改變的情況通知給觀察者褐奴。這么做的好處就是,比如在一個Activity里面請求了網(wǎng)絡(luò)更新這個Activity A界面下的數(shù)據(jù)于毙,但是如果數(shù)據(jù)還沒有請求回來這時候用戶跳轉(zhuǎn)到了另一個Activity B敦冬,這時候如果這個數(shù)據(jù)是被LiveData所持有的,那么這個被網(wǎng)絡(luò)請求更新的數(shù)據(jù)就不會通知給Activity A望众。
LiveData的處理邏輯如下圖所示:
3.1 setValue()
當(dāng)調(diào)用LiveData的setValue(T value)方法時匪补,將設(shè)置LiveData持有的數(shù)據(jù)。判斷是否有活躍的觀察者烂翰,這里的活躍觀察者指觀察者綁定的LifecycleOwner中的Lifecycle處于STARTED和RESUMED狀態(tài)的觀察者夯缺,如果有的話,將更新的數(shù)據(jù)發(fā)送給這些處于活躍狀態(tài)的觀察者甘耿。
3.2 observe()
當(dāng)調(diào)用的LiveData的observe(LifecycleOwner owner, Observer observer)方法時踊兜,根據(jù)情況會有不同的處理。如果LifecycleOwner處于DESTROYED狀態(tài)佳恬,那么這個調(diào)用將被完全忽略捏境。如果它不是DESTROYED于游,那么此時觀察者Observer將被添加到LiveData的觀察者列表中,同時該觀察者會LifecycleOwner綁定垫言,如果LifecycleOwner的生命周期狀態(tài)變成DESTROYED贰剥,那么和這個LifecycleOwner綁定的觀察者會自動被移除,這么做的好處就是可以避免很多可能會出現(xiàn)的內(nèi)存泄漏筷频。同時如果之前LiveData已經(jīng)被設(shè)置過數(shù)據(jù)了蚌成,那么觀察者會立刻接收到最新的數(shù)據(jù)。
如果之前LiveData沒有觀察者觀察它凛捏,那第一次接受觀察者會回調(diào)LiveData的onActive()方法担忧。這個方法里面可以執(zhí)行一些數(shù)據(jù)拉取操作,使數(shù)據(jù)處于處于最新狀態(tài)坯癣,回調(diào)這個方法意味著該LiveData正在被使用中瓶盛。
3.3 removeObserver()
這個方法有兩個重載方法 removeObserver(Observer observer)和 removeObservers(LifecycleOwner owner) 一個是移除觀察者,一個是移除和該LifecycleOwner所綁定的所有觀察者示罗。
如果LiveData的觀察者列表中不存在活躍觀察者了惩猫,也就是說沒有一個觀察者綁定的LifecycleOwner的Lifecycle處于 STARTED 或者RESUMED狀態(tài)。這時候LiveData會回調(diào)onInactive()鹉勒。這時候就算其持有的數(shù)據(jù)更新了帆锋,也不會發(fā)起通知。
3.4 其他方法
① hasActiveObservers():檢查LiveData中是否有活躍的觀察者禽额。
② hasObservers():檢查LiveData中是否有觀察者。
③ observeForever(Observer observer):用于將一個Observer添加到一個活躍列表中皮官,該列表將始終保持ACTIVE狀態(tài)脯倒,因此永遠(yuǎn)不會自動從Observer實例列表中移除它。要移除此Observer時必須手動調(diào)用removeObserver()捺氢。
④ postValue(T value):在主線程中給LiveData設(shè)置值藻丢。
Tips:LiveData中的setValue(T value)、postValue(T value)都是protected摄乒,也就是說只能自己或者它的繼承類進(jìn)行調(diào)用悠反。如果想在外面調(diào)用這些方法可以使用它的繼承類MutableLiveData。
4馍佑、ViewModel
4.1 ViewModel實現(xiàn)
ViewModel這個類設(shè)計出來的目的是為了解決configuration 改變時候斋否,Activity會重建,這時候里面的數(shù)據(jù)不易保存的問題拭荤。有了它Activity或者Fragment就可以不需要承擔(dān)保留數(shù)據(jù)的責(zé)任了茵臭,可以把這些事情交給ViewModel,做到很好的數(shù)據(jù)和視圖的解耦舅世。同時ViewModel會在configuration 更改時自動保留數(shù)據(jù)旦委。
官方給的建議是將LiveData和ViewModel配合來使用奇徒。當(dāng)不需要ViewModel時(比如Activity調(diào)用finish()方法),ViewModel會回調(diào)onCleared()方法缨硝,之后會銷毀自己摩钙。這一好處也是避免了內(nèi)存泄漏的情況發(fā)生。
例子如下:
public class MyViewModel extends ViewModel {
private MutableLiveDatam<Integer> mValue= new MutableLiveData<>();
public LiveData getValue(){
return mValue;
}
public void setValue(Integer value ){
mValue.setValue(value);
}
}
Tips: ViewModel可能比它所涉及的一些Activity/Fragment實例存活時間更長查辩。因此不要保留 Activity的Context和View相關(guān)的任何引用腺律,不然可能引起內(nèi)存泄漏。如果想引用Application的Context宜肉,可以使用AndroidViewModel匀钧,可以通過其getApplication()來獲取。
4.2 ViewModel使用
ViewModel的創(chuàng)建不能通過簡單的new對象來進(jìn)行谬返。需要通過activity / fragment 獲取ViewModel實例之斯。為此,需要訪問一個名為ViewModelProviders的輔助類?遣铝,通過這樣獲取的ViewModel對于一個activity 只有一份:
MyViewModel mMyViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel .class);
ViewModelProviders這個類佑刷,本質(zhì)上其實是一個工廠類。這個類內(nèi)部包含了一個ViewModelStore實例酿炸,它負(fù)責(zé)存儲創(chuàng)建的ViewModels瘫絮。同時可以使用ViewModelProvider的get()方法來獲取作為參數(shù)傳入的ViewModel類型的實例。該方法源碼如下:
@NonNull@MainThreadpublicT get(@NonNull String key, @NonNull Class modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
// 無需檢查之間返回
return (T) viewModel;
} else {
if (viewModel != null) {
// 輸出警告日志
}
}
// 創(chuàng)建一個ViewModel 對象并存入ViewModelStore填硕。
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
如源碼所示麦萤,當(dāng)調(diào)用此get()方法時,ViewModelProvider將檢查ViewModelStore是否已具有該類類型的現(xiàn)有ViewModel扁眯,如果是壮莹,則將返回它。但是姻檀,如果不存在命满,那么將創(chuàng)建一個新的ViewModel并將其添加到ViewModelStore中。
獲取到ViewModel 就可以使用里面的屬性和方法來進(jìn)行操作了绣版。下面說明下ViewModel存在的意義胶台。
4.3 ViewModel 意義
ViewModel 被設(shè)計出來,不僅為了解決上面所說的configuration改變時候能保留數(shù)據(jù)杂抽。其真正意義在于以下幾個方面:
① 職責(zé)分離:使Activity/Fragment不用再負(fù)責(zé)從某些數(shù)據(jù)源獲取數(shù)據(jù)诈唬,只需要負(fù)責(zé)展示數(shù)據(jù)就好,同時還消除了在配置更改時保留數(shù)據(jù)對象實例的引用的責(zé)任默怨。這兩個職責(zé)都轉(zhuǎn)給了ViewModel讯榕。
② 簡化對沒用數(shù)據(jù)的清理:當(dāng)Activity/Fragment負(fù)責(zé)清理數(shù)據(jù)的操作時,需要使用大量代碼來清理這些請求。但是將這些清理操作放到ViewModels onCleared()方法中愚屁,這些資源在Activity結(jié)束時會自動清除济竹。
③ 減少類的膨脹:由于職責(zé)的轉(zhuǎn)移,Activity/Fragment刪除了許多用于處理請求霎槐,狀態(tài)持久性和注銷數(shù)據(jù)的代碼送浊。這些代碼通常會導(dǎo)致Activity/Fragment變得非常臃腫,這樣的代碼會難以擴(kuò)展和維護(hù)丘跌。使用ViewModels可以幫助開發(fā)者緩解Activity/Fragment的膨脹袭景,使各個類的職責(zé)盡可能單一。
④ 容易測試:職責(zé)的分離會使測試這些職責(zé)更容易闭树,而且還可以產(chǎn)生更細(xì)粒度的測試用例耸棒。