前言
Android Architecture Components,簡稱 AAC ,是 Google IO 2017 大會新推出的 app 架構(gòu),從使用感受上說是對 MVVM 的官方加強,AAC 可以解決我們常見的一些內(nèi)存泄露的場景使用,添加了更易操作的 view 生命周期管理。
拓展一下,MVC / MVP / MVVM 這種代碼架構(gòu)組織方式都是基于:UI 驅(qū)動數(shù)據(jù) ,我們常用的 EventBus 框架則是:數(shù)據(jù)驅(qū)動 UI。數(shù)據(jù)和 UI 誰驅(qū)動誰,這其實就是我們架構(gòu)的核心,可以決定我們?nèi)绾谓M織代碼機構(gòu),如何具體的書寫代碼。
仔細(xì)想了2天,我說下自己的體會:
UI 驅(qū)動數(shù)據(jù)
我管這種方式叫:主動持有型。大家仔細(xì)想想,我們在頁面中 findviewbyid 持有控件的對象,然后給UI 控件注冊交互方法,頁面對象持有 Persenter 邏輯對象,Persenter 邏輯持有數(shù)據(jù)層對象,這一層層對象之間都是通過上游對象調(diào)用下游對象的方法,接受數(shù)據(jù)或是傳入 callback 回調(diào)的方式,實現(xiàn)這一層層上下游對象之間的交互的,這一層層上下游對象擁有不同的生命周期,相互支持,就容易造成內(nèi)存泄露,最大的問題是對象類型的強依賴,代碼解耦不容易,我們在做組件化很麻煩,需要寫大量的公共中間通訊接口,有時候還不一定能解決強依賴的問題。我覺得不太適合如今 越來越大型的 app 開發(fā)和公司內(nèi)部多 app 聯(lián)動開發(fā)的需求了。數(shù)據(jù)驅(qū)動 UI
我管這種方式叫:事件驅(qū)動型。我們在使用 EventBus 時發(fā)送一個 info 數(shù)據(jù)對象出去就行,我們不管有多少對象會處理這個數(shù)據(jù)對象,如果有10個對象會消費這個數(shù)據(jù)讀寫,那么在 EventBus 架構(gòu)中我們不用持有這10個對象,就避免了對象類型的強耦合,給我們使用組件化帶來了巨大的便利,這就是我們組件化,甚至插件化改造當(dāng)前項目的基石。一個 info 數(shù)據(jù)對象就是一個事件,這樣看我們就是用數(shù)據(jù)來驅(qū)動 UI 了。
之前我頁嘗試過使用 EventBus 來搭建我的事件驅(qū)動型 app 架構(gòu),嘗試過會發(fā)現(xiàn)問題很多,info 類爆炸,內(nèi)存泄露等問題很難解決,不是我一個人恩那個解決的。但是今天我們帶來的這個官方的 AAC 架構(gòu) ,就是基于事件驅(qū)動型的新的架構(gòu)體系,大大解決了我們在組件化過程中的痛點,可以實現(xiàn)高度解耦。
大家可以試想,EventBus 是一個中間件,一個可以在所有 module 中通用的,EventBus 內(nèi)部維護(hù)了所有的消費 info 數(shù)據(jù)的消費對象,EventBus.getInstance() 我們可以注冊消費對象,這就簡單的實現(xiàn)了 module 之間的解耦,module A 提供數(shù)據(jù),不論游多少 module 去消費這個 info 數(shù)據(jù),module A 都可以不關(guān)心,頁不用持有這些消費 module 的引用。這就是基于事件的 app 架構(gòu)的基礎(chǔ),之后不論游多復(fù)雜的架構(gòu),都是基于這個思想的,基于事件的架構(gòu)核心痛點就是:高度解耦。具體應(yīng)用應(yīng)用就是為組件化,插件化掃平障礙
大家也可以看看我摘錄別人博客的一些思路:

我說的也是我自己個人的認(rèn)識,有異議歡迎大家在下面噴我啊,一定要噴啊......
學(xué)習(xí)資料
AAC 的是去年出的,第一時間獲得了高關(guān)注,奈何本人小白一個,現(xiàn)在才剛剛看到這個 AAC 架構(gòu),網(wǎng)上的學(xué)習(xí)資料很多,基礎(chǔ)的部分大家還是詳細(xì)去看看我貼出來的資料,我就簡單的總結(jié)一下知識點,然后會重點說一下我的認(rèn)識。
基礎(chǔ)學(xué)習(xí)資料:
- AAC(Android Architecture Components)
- 淺談Android Architecture Components
- Android 項目最新架構(gòu)
- Android 架構(gòu)組件 Room 介紹及使用
- Android 應(yīng)用架構(gòu)組件(Architecture Components)實踐
官方demo:
-
BasicSample
演示如何使用a SQLite database 和 Room做持久化,同時也使用了ViewModel和LiveData。 -
PersistenceContentProviderSample
演示如何使用Room通過 Content Provider暴露數(shù)據(jù)。 -
GithubBrowserSample
一個使用 Architecture component,Dagger以及Github API的高級示例,需要Android Studio 2.4。
官方視頻學(xué)習(xí)資源:
-
架構(gòu)組件之 ViewModel | 中文教學(xué)視頻
官方稱 Lifecycles 這3個組件為生命周期管理組件,我覺得已經(jīng)不僅僅是生命周期管理了,而是把 app 架構(gòu)改造成響應(yīng)式架構(gòu)了,整個 app 的事件和數(shù)據(jù)流動完全基于 Observable 和 Observer 的訂閱來實現(xiàn)。觀官方問法當(dāng)所言,ViewModel 是解決 UI 和數(shù)據(jù)之間的邏輯,但是不宜讓 ViewModel 處理過多的頁面邏輯,若是頁面邏輯和設(shè)置比較復(fù)雜,Persenter 還是有必要存在的。
開源學(xué)習(xí) demo:
-
awaker
一個挺不錯的 demo ,很詳細(xì)的使用了 AAC 框架,代碼封裝的不錯。個人感官,AAC 框架使用的有些畏手畏腳,很中規(guī)中矩,AAC 參與獲取數(shù)據(jù),刷新頁面顯示,沒有探討更深入的用 AAC 把 app 架構(gòu)向數(shù)據(jù),事件流方向修改。另外數(shù)據(jù)層中有些職責(zé)不清晰,在 respositroy 在最外層類內(nèi)封裝了 respositroyHelp 具體頁面實現(xiàn)層的情況下, respositroy 最外層類還是涉及到一些具體的業(yè)務(wù)邏輯,另外 SQL 數(shù)據(jù)庫層不是和網(wǎng)絡(luò)層同一個級別的,頁面有管理層對象。但是總體來說,還是不錯的, 尤其是 數(shù)據(jù)層適合一看,查漏補缺,看別人的實現(xiàn)完善自己的實現(xiàn)。 -
ArchitecturePractice
這個 demo 比較簡單,數(shù)據(jù)層頁很簡單,但是數(shù)據(jù)層層次很清晰,適合看過上面的 demo 再來看看這個反思一下數(shù)據(jù)層到底應(yīng)該怎么寫。 - 使用Android Architecture Component開發(fā)應(yīng)用(附demo)
本文 demo:
-
BW_AAC_Demo
看點是用 LiveData 改造了一下 repositroy 數(shù)據(jù)層,UI 層通過 ViewModule 獲取這個 LiveData,建立通道聯(lián)系刷新數(shù)據(jù)。簡單用 RXJava 延遲 2 秒發(fā)送一條數(shù)據(jù),模擬一下網(wǎng)絡(luò)請求。
補充資料:
-
[譯] Architecture Components 之 Guide to App Architecture
翻譯的 AAC 官方文檔,詳細(xì)講解了官方的學(xué)習(xí) demo,里面是一個系列博客,詳細(xì)分節(jié)講解了 AAC 的每個部分。各位要是看我的文章哪里看糊涂了,不妨去這里尋找答案。 -
安卓架構(gòu)組件-分頁庫
這個有意思啊,使用 AAC 組件開發(fā)列表分頁加載,作者使用 PagerList 來管理分頁狀態(tài),隔壁根據(jù)分頁狀態(tài)從 DataSource 中獲取數(shù)據(jù),作者使用數(shù)據(jù)庫舉例子的,remote 遠(yuǎn)程資源同樣也可以,值得一看。 - 淺析MVP中model層設(shè)計【從零開始搭建android框架系列(7)】
- Android 生命周期架構(gòu)組件與 RxJava 完美協(xié)作
AAC 主要內(nèi)容
-
Lifecycle
生命周期管理,把原先Android生命周期的中的代碼抽取出來,如將原先需要在onStart()等生命周期中執(zhí)行的代碼分離到Activity或者Fragment之外。 -
LiveData
一個數(shù)據(jù)持有類,持有數(shù)據(jù)并且這個數(shù)據(jù)可以被觀察被監(jiān)聽,和其他Observer不同的是,它是和Lifecycle是綁定的,在生命周期內(nèi)使用有效,減少內(nèi)存泄露和引用問題。 -
ViewModel
代替 persenter 的角色,生命周期長于 activity / fragment ,一種新的保存數(shù)據(jù)的方式。同時是與Lifecycle綁定的,使用者無需擔(dān)心生命周期??梢栽诙鄠€Fragment之間共享數(shù)據(jù),比如旋轉(zhuǎn)屏幕后Activity會重新create,這時候使用ViewModel還是之前的數(shù)據(jù),不需要再次請求網(wǎng)絡(luò)數(shù)據(jù)。 -
Room
Google 推出的一個Sqlite ORM庫,不過使用起來還不錯,使用注解,極大簡化數(shù)據(jù)庫的操作,有點類似Retrofit的風(fēng)格。
上面4個就是這次 AAC 架構(gòu)的核心 API 了,通過這幾個 API 我們可以搭建一套基于事件的 app 架構(gòu)出來,LiveData 和其他一些 API 可以簡單的看做是 Google 版的 RXJAVA ,只不過是針對 android 系統(tǒng)的,功能上也是很簡單,沒有 RXJAVA 那么強大的變換和線程控制。但是這正是我們所需要的,因為有了 RXJAVA ,我們在復(fù)雜的業(yè)務(wù)場景中用 RXJAVA 就好了,LiveData 使用簡單,學(xué)習(xí)成本低,我們用來搭建基于數(shù)據(jù)流的響應(yīng)式架構(gòu)體系的 app 是最合適的。
AAC 架構(gòu)圖如下:

添加依賴
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' } //添加此行
}
}
//For Lifecycles, LiveData, and ViewModel
implementation 'android.arch.lifecycle:common-java8:1.1.1'
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'android.arch.lifecycle:runtime:1.1.1'
//For Room
compile "android.arch.persistence.room:runtime:1.1.0-alpha1"
annotationProcessor "android.arch.persistence.room:compiler:1.1.0-alpha1"
// For Room RxJava support, add:
compile "android.arch.persistence.room:rxjava2:1.1.0-alpha1"
上面的依賴使用的是 Java8,不用添加 apt 或者 kapt 或者 annotationProcessor,但是需要設(shè)置 compileOptions
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
Lifecycle
很多文章說的廢話多,不直接, Android 頁面生命周期加強,把頁面的生命周期變成一個 Observable ,這個 Observable 我們無法直接使用,而是配合注解寫在需要 hook 生命周期的位置,最大的好處就是脫離了 callback 或是 Proxy 代理類,在代碼上靈活太多了,Lifecycle 會掃描所有代碼中有標(biāo)記的方法,然后注冊給生命周期的 Observable 對象里面去,這種寫法是不是和 EventBus 一樣啊。最直接的在寫代碼時這就是 基于事件的魅力,我們不用再耗費心神設(shè)計代碼結(jié)構(gòu),寫那些 callback / Proxy 代理類了。
所以 AAC 這個基于事件的架構(gòu)是學(xué)起來最通透的,一切都是 Observable / Observer,都是觀察者和被觀察者的關(guān)系,一切都是基于注冊的方式運行。
既然一切都是 Observable / Observer 的,那么管理頁面生命周期的 Observable / Observer 哪里來呢,這就要說到 LifecycleActivity / LifecycleFragment 了,我是用 API 26做基準(zhǔn)編譯代碼的,AppCompatActivity / V4 包下的 Fragment 都已經(jīng)兼容了 AAC 架構(gòu)了,所以 LifecycleActivity / LifecycleFragment 過時了,大家注意一下:


然后我們通過這個 API 可以獲取這個 Observable Lifecycle
Lifecycle lifecycle = getLifecycle();
那么這個 Observer 呢,我們直接 new 一個 LifecycleObserver 對象出來也行,或是某個類實現(xiàn)這個接口也行,最后注冊到 Observable 就行,下面看代碼:
MyLifecyleTextView 實現(xiàn) LifecycleObserver 接口
@SuppressLint("AppCompatCustomView")
public class MyLifecyleTextView extends TextView implements LifecycleObserver {
public MyLifecyleTextView(Context context) {
super(context);
}
public MyLifecyleTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyLifecyleTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public MyLifecyleTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void creat() {
Log.d("AAA", "oncreat...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void start() {
Log.d("AAA", "onstart...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void resume() {
Log.d("AAA", "onresume...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void pasue() {
Log.d("AAA", "onpause...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void stop() {
Log.d("AAA", "onstop...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void destroy() {
Log.d("AAA", "ondestroy...");
}
}
綜合使用
public class MainActivity extends AppCompatActivity {
private MyLifecyleTextView tx_lifectle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tx_lifectle = findViewById(R.id.tx_lifecley);
getLifecycle().addObserver(tx_lifectle);
getLifecycle().addObserver(new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void start() {
Log.d("AAA", "new_onstart...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void resume() {
Log.d("AAA", "new_onresume...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void pasue() {
Log.d("AAA", "new_onpause...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void stop() {
Log.d("AAA", "new_onstop...");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void destroy() {
Log.d("AAA", "new_ondestroy...");
}
});
}
}
上面的代碼基本包含了 Lifecycle 的常用應(yīng)用場景了,不管你事讓某個自定義 view hook 某個生命周期也行,還是直接注冊一個觀察者對象也行,在代碼上我們完全脫離了頁面生命周期函數(shù)里,頁面或是 penserent ,viewmodule 都不用再保存相關(guān)的 callback ,proxy,listener 在頁面的生命周期函數(shù)里執(zhí)行了,在 app 代碼層面實現(xiàn)了基于觀察者模式的代碼思路。減少強制持有屬性,功能,代理對象,這也是一種解耦啊,和以前對象.方法比起來,代碼是越寫越靈活啊,這就是趨勢啊。
好了,上面 XBB 了一下,Lifecycle 還沒說完呢,我們了解了 Lifecycle 如何使用,代碼里我們可以看到有很多帶注解的函數(shù)
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void stop() {
Log.d("AAA", "new_onstop...");
}
既然說了 Lifecycle 像 EventBus ,那么大家就不會對這注解函數(shù)陌生了吧,我來說說這個 Lifecycle.Event.ON_STOP 。API 的名字起來很規(guī)矩,大家一看應(yīng)該就知道了,ON_STOP 就是代表了 onStop() 這個生命周期函數(shù)了,以此類推就不用多重復(fù)了
另外通過 Lifecycle 我們還可以獲取當(dāng)前 view 的生命周期狀態(tài),這在之前是需要自己去維護(hù)的,有了這個 API 我們在很多時候會方便很多啊。
Lifecycle.State currentState = getLifecycle().getCurrentState();
if( currentState == Lifecycle.State.STARTED ){
xxxxxxxxx
}
另外官方有 Lifecycle 對應(yīng)的生命周期圖,大家看看

Lifecycle 注冊的生命周期回調(diào)方法需要說一下是即使生效的,這點必須要說清楚,不說有的童鞋可能會以為第一次無效,其實我們想想,對于聲明周期來說,第一次無效是不符合設(shè)計思路和場景需求的。
Lifecycle 的最后我得數(shù)據(jù)說一下這個接口 LifecycleRegistryOwner ,AppCompatActivity / V4 包下的 Fragment 都是通過實現(xiàn)這個接口來兼容 AAC 架構(gòu)的,其實這個接口很簡單,里買就一個方法,需要我們返回 Lifecycle 的核心功能類 LifecycleRegistry 即可??创a,自己實現(xiàn) Lifecycle :
import android.arch.lifecycle.LifecycleRegistry;
import android.arch.lifecycle.LifecycleRegistryOwner;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity implements LifecycleRegistryOwner {
private LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
proxy.zj.com.lifecycledemo.MyTv mTv = findViewById(R.id.dfttv);
mTv.setLifecycle(getLifecycle());
getLifecycle().addObserver(mTv);
mTv.setLifeCycleEnable(true);
}
@Override
public LifecycleRegistry getLifecycle() {
return lifecycleRegistry;
}
}
其實我們用不到 LifecycleRegistryOwner 這個借口,但是為啥要說呢,系統(tǒng)只是在 Activity 和 Fragment 層面兼容了 AAC ,我們要是需要自己的自定義 view 對外提供聲明周期管理的話記得自己實現(xiàn)了。按著上面的代碼來就行,很簡單,一看就會,不會來找我。
摘一段官方文檔的翻,出自:[譯] Architecture Components 之 Handling Lifecycles
Lifecycles 的最佳實踐
保持 UI 控制器(Activity 和 Fragment)盡可能的精簡。它們不應(yīng)該試圖去獲取它們所需的數(shù)據(jù);相反,要用 ViewModel 來獲取,并且觀察 LiveData 將數(shù)據(jù)變化反映到視圖中。
嘗試編寫數(shù)據(jù)驅(qū)動(data-driven)的 UI,即 UI 控制器的責(zé)任是在數(shù)據(jù)改變時更新視圖或者將用戶的操作通知給 ViewModel。
將數(shù)據(jù)邏輯放到 ViewModel 類中。ViewModel 應(yīng)該作為 UI 控制器和應(yīng)用程序其它部分的連接服務(wù)。注意:不是由 ViewModel 負(fù)責(zé)獲取數(shù)據(jù)(例如:從網(wǎng)絡(luò)獲?。?。相反,ViewModel 調(diào)用相應(yīng)的組件獲取數(shù)據(jù),然后將數(shù)據(jù)獲取結(jié)果提供給 UI 控制器。
使用 Data Binding 來保持視圖和 UI 控制器之間的接口干凈。這樣可以讓視圖更具聲明性,并且盡可能減少在 Activity 和 Fragment 中編寫更新代碼。如果你喜歡在 Java 中執(zhí)行該操作,請使用像 Butter Knife 這樣的庫來避免使用樣板代碼并進(jìn)行更好的抽象化。
如果 UI 很復(fù)雜,可以考慮創(chuàng)建一個 Presenter 類來處理 UI 的修改。雖然通常這樣做不是必要的,但可能會讓 UI 更容易測試。
不要在 ViewModel 中引用 View 或者 Activity 的 context。因為如果 ViewModel 存活的比 Activity 時間長(在配置更改的情況下),Activity 將會被泄漏并且無法被正確的回收。
liveData
liveData 簡單來說就是一個可以根據(jù)觀察者自身生命周期,在觀察者需要結(jié)束時自動解綁的 Observable,并且結(jié)合了 DataBingding 的特點,liveData 自身數(shù)據(jù)改變時可以通知所有的觀察者對象。哈哈,所以說完上面 Lifecycle 才能來看 liveData ,這個生命周期管理自然是依托 Lifecycle 了,他倆本身就是一個體系下的東東啊。
liveData 是 abstract 的一個類,有3個關(guān)鍵方法:
- onActive
liveData 注冊的觀察者數(shù)量從 0 到 1時會執(zhí)行,相當(dāng)于初始化方法 - onInactive
liveData 注冊的觀察者數(shù)量回到 0 時會執(zhí)行 - setValue
數(shù)據(jù)改變通知所有觀察者
其他不多說,先來看看一個最簡單的 liveData 例子:
- applicaton 中對外提供一個 liveData 對象
- MainActivity 獲取這個 liveData 然后注冊一個觀察者對象
- MainActivity 可以啟動一個新的頁面
MyApplication
public class MyApplication extends Application {
private static MyApplication INSTANCE;
public MyLiveData liveData;
public static MyApplication getInstance() {
return INSTANCE;
}
@Override
public void onCreate() {
super.onCreate();
INSTANCE = this;
liveData = new MyLiveData();
}
LiveData
public class MyLiveData extends LiveData<String> {
@Override
protected void setValue(String value) {
super.setValue(value);
Log.d("BBB", "setValue..." + value);
}
@Override
protected void onActive() {
super.onActive();
Log.d("BBB", "onActive...");
}
@Override
protected void onInactive() {
super.onInactive();
Log.d("BBB", "onInactive...");
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private MyLifecyleTextView tx_lifectle;
private Button btn_01;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tx_lifectle = findViewById(R.id.tx_lifecley);
getLifecycle().addObserver(tx_lifectle);
getLifecycle().addObserver(new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void start() {
Log.d("AAA", "new_onstart...");
}
});
btn_01 = findViewById(R.id.btn_one);
btn_01.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// data.setValue("AAAAAAAAA");
startActivity(new Intent(MainActivity.this, SecondActivity.class));
}
});
MyApplication.getInstance().liveData.observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
Log.d("BBB", "數(shù)據(jù)改變..." + s);
}
});
}
liveData 是可以使用泛型的,Google 推出 liveData 的初衷,就是用來包裹數(shù)據(jù),包裝成一個 Observable 的,所以一定要支持泛型才能使用的方便啊。
這里提醒一句,有人推薦使用 MutableLiveData ,我的確是看到游 demo 使用 MutableLiveData 了。
這個例子,我們重點來看一下 onActive / onInactive 這個2個方法和觀察者生命周期的互動,這點很重要,弄懂這點,這2個方法我們才能得心應(yīng)手,要不會出問題的。 我會打印 mainactivity 的生命周期函數(shù) 和 livadata 的相關(guān)方法



根據(jù)上文所說, liveData 注冊的觀察者數(shù)量從 0 到 1時會執(zhí)行 onActive , liveData 注冊的觀察者數(shù)量回到 0 時會執(zhí)行 onInactive ,我們看看這個經(jīng)典的例子,一個頁面啟動另一個頁面再回來,這包含一個完整的生命周期了。
那我們要是再第二個頁面 oncreat 函數(shù)里面也注冊一個觀察者呢,大家猜猜啊,挺有意思的。


觀察以上,可以得出一下結(jié)論:
- liveData 觀察者計數(shù)以 onPause 為分界點,觀察者走 onPause 生命周期函數(shù),liveData 觀察者計數(shù)會 -1,觀察者走 onStart 生命周期函數(shù),liveData 觀察者計數(shù)會 +1
- liveData 的 onActive / onInactive 方法是根據(jù)注冊的觀察者數(shù)量是否為0觸發(fā)的,不是每一個觀察者的生命周期變動都會觸發(fā) onActive / onInactive 這2個方法,只有再觀察者數(shù)量為0時才行,這點一定要注意
另外我們可以獲取 liveData 里面的數(shù)據(jù)
liveData.getValue();
觀察者在注冊到 liveData 后,不會觸發(fā)執(zhí)行一次 setvalue 方法,這點搞清楚基本就 OK 了
2019.5.02 補充
liveData 內(nèi)部有值的情況下,首次注冊 liveData 也是會觸發(fā)一次 setvalue 相應(yīng)的,setvalue 沒有值就不會。例子:A -> B -> A -> B ,第一次從 B 返回事,因為 liveData 已經(jīng)有值了,A 此時會觸發(fā)一次 setvalue ,再次從 A 到 B,還是因為 liveData 已經(jīng)有值了,B 雖然是新創(chuàng)建的 Activity ,但是因為 liveData 由數(shù)值,還是會觸發(fā)一次 setvalue
總之就是只要 liveData 內(nèi)部有數(shù)值,那么注冊的頁面主要生命周期可以相應(yīng)了,那么就會觸發(fā)一次 setvalue,這里我用的還好是最新的 1.1.1 的版本,liveData 這種機制不太適合大多數(shù)場景,還是推薦使用 RxBus 可以相應(yīng)的更精確
Lifecycle 和 liveData 綜合使用的例子
看這個 UserData 他可以在 view 生命周期變動時調(diào) setvalue 方法,通知所有觀察者數(shù)據(jù)有變動
public class UserData extends LiveData implements LifecycleObserver {
private static final String TAG = "UserData";
public UserData() {
}
@Override
protected void onActive() {
super.onActive();
Log.e(TAG, "onActive");
}
@Override
protected void onInactive() {
super.onInactive();
Log.e(TAG, "onInactive");
}
@Override
protected void setValue(Object value) {
super.setValue(value);
Log.e(TAG, "setValue");
}
}
這種情況比較少使用,你想這個 liveData 要和具體一個 view 的生命周期綁定,根據(jù)生命周期變動處理數(shù)據(jù),發(fā)送新數(shù)據(jù)給所有注冊者。在組件化的思路里,比較適合一個模塊對外提供公共數(shù)據(jù),然后這個模塊有變動或是注銷,再通知其他有數(shù)據(jù)關(guān)聯(lián)的模塊數(shù)據(jù)變動。
LiveData 有以下優(yōu)點:
沒有內(nèi)存泄漏:因為 Observer 被綁定到它們自己的 Lifecycle 對象上,所以,當(dāng)它們的 Lifecycle 被銷毀時,它們能自動的被清理。
不會因為 activity 停止而崩潰:如果 Observer 的 Lifecycle 處于閑置狀態(tài)(例如:activity 在后臺時),它們不會收到變更事件。
始終保持?jǐn)?shù)據(jù)最新:如果 Lifecycle 重新啟動(例如:activity 從后臺返回到啟動狀態(tài))將會收到最新的位置數(shù)據(jù)(除非還沒有)。
正確處理配置更改:如果 activity 或 fragment 由于配置更改(如:設(shè)備旋轉(zhuǎn))重新創(chuàng)建,將會立即收到最新的有效位置數(shù)據(jù)。
資源共享:可以只保留一個 MyLocationListener 實例,只連接系統(tǒng)服務(wù)一次,并且能夠正確的支持應(yīng)用程序中的所有觀察者。
不再手動管理生命周期你可能已經(jīng)注意到,fragment 只是在需要的時候觀察數(shù)據(jù),不用擔(dān)心被停止或者在停止之后啟動觀察。由于 fragment 在觀察數(shù)據(jù)時提供了其 Lifecycle,所以 LiveData 會自動管理這一切。
看一個經(jīng)典的 LiveData 應(yīng)用例子
一個定位的例子,這里寫的簡單,manage ,factroy ,都沒寫,但是這個例子展示了:如何用 LiveData 包裝數(shù)據(jù),結(jié)合單例作為 app 的全局?jǐn)?shù)據(jù)使用,這個單例可以寫再這個自定義的 LiveData 里,也可以寫在 manage 里有管理類來管理要更好一點
public class LocationLiveData extends LiveData<Location> {
private static LocationLiveData sInstance;
private LocationManager locationManager;
@MainThread
public static LocationLiveData get(Context context) {
if (sInstance == null) {
sInstance = new LocationLiveData(context.getApplicationContext());
}
return sInstance;
}
private SimpleLocationListener listener = new SimpleLocationListener() {
@Override
public void onLocationChanged(Location location) {
setValue(location);
}
};
private LocationLiveData(Context context) {
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
@Override
protected void onActive() {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
}
@Override
protected void onInactive() {
locationManager.removeUpdates(listener);
}
}
Transformations
LiveData 就是一個 Observable ,那么官方提供了一個 Transformations 類,包含 map 和 switchMap 轉(zhuǎn)換操作,和 Rxjava 的 map 、flatMap 一樣,
- Transformations.map()
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
user.name + " " + user.lastName
});
- Transformations.switchMap()
private LiveData<User> getUser(String id) {
// ... 這里可以通過遠(yuǎn)程獲取數(shù)據(jù)
}
LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
map() 方法接受一個數(shù)據(jù),返回一個新的數(shù)據(jù),這個看著不難,switchMap() 方法接受一個數(shù)據(jù),然后依賴另一個 LiveData 加工,然后返回數(shù)據(jù)。要是看著不太懂的話,看這里:[譯] Architecture Components 之 LiveData
ViewModel
這個最好理解,ViewModel 就是 MVP 中,P 的角色,當(dāng)然 ViewModel 還有他的獨特之處。ViewModel 的生命周期雖然總體上還是跟著 view 的,但是 ViewModel 存在的時間比 view 要長一些。我們看看這幾個場景:
- 屏幕旋轉(zhuǎn),系統(tǒng)主動殺死造成的 Activity 或者 Fragment 被銷毀或重新創(chuàng)建,所以保存于其中的數(shù)據(jù)有可能會丟失
- 在 Activity 或者 Fragment 中會經(jīng)常發(fā)起一些需要一定時間才會返回結(jié)果的異步請求調(diào)用

ViewModel 生命周期圖表明了 ViewModel 的生命周期是有些區(qū)別,單總體趨同與 view 的生命周期的,提供了一種新的 view 數(shù)據(jù)保存模式,比如屏幕旋轉(zhuǎn)時 activity 重新創(chuàng)建 ViewModel 還是原來那個對象。
ViewModel 是個基類,需要我們繼承他,沒有特殊方法需要去處理,集成完后,直接創(chuàng)建對象就可以使用了。
MyViewModule myViewModule2 = ViewModelProviders.of(this).get(MyViewModule.class);
還有一個 AndroidViewModel ,期中可以獲取 application ,只不過這個 application 需要我們自己傳入,另外 ViewModel 的 of 方法還可以接受一個 ViewModelProvider.NewInstanceFactory 的參數(shù),可以支持自定義構(gòu)造方法,想傳幾個參數(shù)都沒問題
public class MyViewModule extends AndroidViewModel {
public String name;
public MyViewModule(@NonNull Application application, String name) {
super(application);
this.name = name;
}
public void show() {
Toast.makeText(getApplication(), "測試...", Toast.LENGTH_SHORT).show();
}
public static class Factroy extends ViewModelProvider.NewInstanceFactory {
public Application application;
public String name;
public Factroy(Application application, String name) {
this.application = application;
this.name = name;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) new MyViewModule(application, name);
}
}
}
創(chuàng)建 MyViewModule 對象
MyViewModule.Factroy factroy = new MyViewModule.Factroy(getApplication(), "AAA");
MyViewModule myViewModule = ViewModelProviders.of(this, factroy).get(MyViewModule.class);
使用 ViewModule 可以在同一個 actitivity 的多個 Fragment 之間共享數(shù)據(jù)
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 onActivityCreated() {
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends LifecycleFragment {
public void onActivityCreated() {
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// 更新 UI
});
}
}
- Activity 不需要知道該通信的任何事情
- Fragment 之間不受相互影響。除了 ViewModel 之外,F(xiàn)ragment 不需要了解彼此,就算一個 Fragment 被銷毀了,另一個也可以正常工作。而且每個 Fragment 都有自己獨立的生命周期,不受其他 Fragment 的影響。
寫到這里其實我們可以看到一個問題,ViewModel 內(nèi)部不應(yīng)該持有外部 view 的引用,ViewModel 的聲明周期比 Fragment / Activity 都長,ViewModel 要是持有了外部 view 的引用就會造成內(nèi)存泄露,需要注意!
ViewModel 和外部 view 的交互看過上面的大家應(yīng)該都明悟了,就是 LiveData 了,用這個 LiveData 代替 view 的交互接口同 ViewModel 通信,ViewModel 返回 LiveData ,然后 view 獲取這個 LiveData 再去注冊 updata 方法,這樣避免 ViewModel 持有外部 view 造成的內(nèi)存泄露
ViewModel vs SavedInstanceState
ViewModels 提供了一種在配置更改時保存數(shù)據(jù)的簡便方式,但是如果應(yīng)用進(jìn)程被操作系統(tǒng)殺死,那么數(shù)據(jù)則沒有機會被恢復(fù)。
通過 SavedInstanceState 保存的數(shù)據(jù),存在于操作系統(tǒng)進(jìn)程的內(nèi)存中。當(dāng)用戶離開應(yīng)用數(shù)個小時之后,應(yīng)用的進(jìn)程很有可能被操作系統(tǒng)殺死,通過 SavedInstanceState 保存的數(shù)據(jù),則可以在 Activity 或者 Fragment 重新創(chuàng)建的時候,在其中的 onCreate() 方法中通過 Bundle 恢復(fù)數(shù)據(jù)。
Room
谷歌推出的一個Sqlite ORM庫,不過使用起來還不錯,使用注解,極大簡化數(shù)據(jù)庫的操作,有點類似Retrofit的風(fēng)格
不過 Room 還是沒有脫離 SQL 語言,在注解中還是要寫 SQL 語句的,一般移動端的 數(shù)據(jù)庫沒有太高的要求,這樣我們其實可以使用 Room 這個數(shù)據(jù)庫,Room 存的是對象,取的也是對象,是對象類型數(shù)據(jù)庫了。要是 app 項目的數(shù)據(jù)庫要求高的話,在來使用 Room 也是個不錯的選擇
Room 的詳細(xì)學(xué)習(xí)看這個:淺談Android Architecture Components | Android 架構(gòu)組件 Room 介紹及使用
AAC 框架帶給我們的改變
上面我們已經(jīng)基本看過了 AAC 框架新的 API ,經(jīng)過 AAC 改造,我們不用擔(dān)心內(nèi)存泄露的場景了,頁面的生命周期函數(shù)處理可以寫在頁面之外,更靈活了,整個 app 的架構(gòu)可以像 Rxjava 一樣,改成基于數(shù)據(jù)和事件的流式架構(gòu)了,可以讓我們更簡單容易分離,組合代碼結(jié)構(gòu)。
說帶具體的還是 LiveData 對數(shù)據(jù)層的改造對我們影響最大,我們再來看看上面官方給出的 AAC 架構(gòu)圖

Google 官方的頁面,數(shù)據(jù)流程如下:
- Respositroy 判斷環(huán)境,管理緩存,返回數(shù)據(jù)
- ViewModel 管理數(shù)據(jù)的 LiveData
- 頁面獲取 LiveData 注冊 updata 界面更新方法
- 最后 ViewModel 觸發(fā) Respositroy 請求數(shù)據(jù),通過 LiveData 更新數(shù)據(jù)
很明顯,這是一個最簡單的數(shù)據(jù),顯示例子,展示的一個頁面擁有一個 LiveData 對象來更新數(shù)據(jù),這是傳統(tǒng)的邏輯思路。但是大家想想,LiveData 是數(shù)據(jù)流式的,我們完全可以讓 Respositroy 返回一個靜態(tài)的全局的 LiveData ,需要的頁面去注冊 updata 方法,頁面關(guān)閉的時候可以自動接觸綁定,這才是 LiveData 的初衷啊,當(dāng)然使用嘛,不要死板,怎么靈活,怎么簡單,便利,怎么來。
上面涉及到我們對數(shù)據(jù)的應(yīng)用范圍了和類型了,LiveData 的出現(xiàn)讓我們對數(shù)據(jù)的包裝使用產(chǎn)生了一些思考
數(shù)據(jù)的作用范圍我分為3種:
- 單個頁面范圍內(nèi)
- 單個功能模塊范圍內(nèi)(module)
- 整個 app 范圍內(nèi)
數(shù)據(jù)的類型我分為2種:
- 原始數(shù)據(jù)類型,不做處理
- Reponse<Object> ,把數(shù)據(jù)和加載狀態(tài)綜合一起
- Reponse + Object ,把數(shù)據(jù)和加載狀態(tài)分開,這樣可以視情況選擇
結(jié)合不同的數(shù)據(jù)的應(yīng)用范圍,對數(shù)據(jù)的處理:
- 單個頁面范圍
對于單個頁面范圍的 data ,Respositroy 返回非靜態(tài)的 LiveData < Reponse<Object>> 帶加載狀態(tài)的 data - 單個功能模塊范圍內(nèi)(module)
Respositroy 需要單獨成 module ,Respositroy 返回 LiveData <Reponse> ,LiveData < Object> ,有可能這個 module 的數(shù)據(jù),別的 module 也是需要的,但是對于加載狀態(tài)來說只是本功能 module 有意義,其他 module 只關(guān)心 data 的。 - 整個 app 范圍內(nèi)
同上面單個功能模塊范圍內(nèi)(module)的處理,視情況可以不提供加載狀態(tài)的 Reponse
數(shù)據(jù)的經(jīng)典應(yīng)用場景舉例:
- 單個頁面范圍內(nèi)
這是最常見的,我們請求的大數(shù)據(jù)接口都是,比如商品詳情頁,不同 ID 的商品有不同數(shù)據(jù),那么別的頁面顯然是無法使用這個數(shù)據(jù)的 - 單個功能模塊范圍內(nèi)(module)
這個比較少見,是隨著 app 的組件化出現(xiàn)的,經(jīng)典的例子有定位,定位的數(shù)據(jù)只要對外提供靜態(tài)的 LiveData <Adress> 就行,這個定位數(shù)據(jù)隨著定位模塊的卸載而刪除,要是設(shè)計成整個 app 范圍內(nèi)頁無妨,號保存即可。 - 整個 app 范圍內(nèi)
這個場景更少,但是是難設(shè)計的,最考研代碼功底的。比如全局緩存,這個每個 app 都需要,還有個人中心數(shù)據(jù),這個設(shè)計好了非常厲害了,對于編碼水平提供有很大助力啊
總結(jié)一下就是用 LiveData 改造了一下 repositroy 數(shù)據(jù)層,UI 層通過 ViewModule 獲取這個 LiveData,建立通道聯(lián)系刷新數(shù)據(jù),這樣把整個 app 基于數(shù)據(jù)流改造成響應(yīng)式架構(gòu),適應(yīng)組件化,平臺化高度封裝,業(yè)務(wù)模塊分離的需求。
本文 demo 思路
首先本文 demo 如下:
思路是用 LiveData 改造了一下 repositroy 數(shù)據(jù)層,UI 層通過 ViewModule 獲取這個 LiveData,建立通道聯(lián)系刷新數(shù)據(jù)。簡單用 RXJava 延遲 2 秒發(fā)送一條數(shù)據(jù),模擬一下網(wǎng)絡(luò)請求。
比較好的代碼研究資料:
- Architecture Components 之 Guide to App Architecture
- 使用Android Architecture Component開發(fā)應(yīng)用(附demo)
我的 demo 思路如下:

先來看看我的頁面,主界面中游2個紅色背景的 textview 分別用來顯示2個級別的數(shù)據(jù):單次請求的網(wǎng)絡(luò)數(shù)據(jù)和全局?jǐn)?shù)據(jù),全局?jǐn)?shù)據(jù)在另外一個頁面中加載,然后再返回看看 LiveData 的同步效果是否好用。
數(shù)據(jù)層都封裝再 Respositroy 中,Respositroy 持有一個 netDataSource 用于獲取網(wǎng)絡(luò)數(shù)據(jù),然后 Respositroy 處理數(shù)據(jù)然后返回。其中數(shù)據(jù)都是用 response 來包裹,response 中有 code 用來發(fā)送數(shù)據(jù)加載中的各種狀態(tài)

畫了一個簡單的數(shù)據(jù)流動圖,可以看到我這里的 Respositroy 數(shù)據(jù)層封裝的還是比較簡單的,Respositroy 內(nèi)部只維護(hù)了一個 BookNetDataSource 遠(yuǎn)程數(shù)據(jù)源。
來簡單看下代碼:
BookNetDataSource -> 遠(yuǎn)程數(shù)據(jù)源
public class BookNetDataSource {
private Book mPrivateBook = new Book("私有數(shù)據(jù)在此");
private Book mPublicBook = new Book("共有數(shù)據(jù)在此");
public Observable<Book> getPrivateBook() {
return getData(new Book("私有數(shù)據(jù)如如下:private"));
}
public Observable<Book> getPublicBook() {
return getData(new Book("全局?jǐn)?shù)據(jù)如如下: public"));
}
private Observable<Book> getData(final Book book) {
return Observable.timer(2, TimeUnit.SECONDS)
.map(new Function<Long, Book>() {
@Override
public Book apply(Long aLong) throws Exception {
return book;
}
}).subscribeOn(Schedulers.io());
}
}
BookNetDataSource 返回了2個數(shù)據(jù),private 數(shù)據(jù)表示一次性數(shù)據(jù),public 表示全局緩存數(shù)據(jù),用 rxjava 延遲2秒模擬一下網(wǎng)絡(luò)狀態(tài)
BookRespositroy 數(shù)據(jù)層
public class BookRespositroy {
public static MutableLiveData<Response<Book>> PUBLIC_LIVEDATA;
private MutableLiveData<Response<Book>> mBookLiveData;
private BookNetDataSource mBookNetDataSource;
static {
PUBLIC_LIVEDATA = new MutableLiveData<>();
}
public static MutableLiveData<Response<Book>> getPublicLiveData() {
return PUBLIC_LIVEDATA;
}
public static void refreshPublicData() {
PUBLIC_LIVEDATA.setValue(new Response<Book>(Response.CODE_LOADING, null));
new BookNetDataSource().getPublicBook()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Book>() {
@Override
public void accept(Book book) throws Exception {
PUBLIC_LIVEDATA.setValue(new Response<Book>(Response.CODE_SUCCESS, book));
}
});
}
public BookRespositroy() {
mBookNetDataSource = new BookNetDataSource();
mBookLiveData = new MutableLiveData<>();
}
public MutableLiveData<Response<Book>> getPrivateLiveData() {
return mBookLiveData;
}
public void refreshPrivateData() {
mBookLiveData.setValue(new Response<Book>(Response.CODE_LOADING, null));
mBookNetDataSource.getPrivateBook()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Book>() {
@Override
public void accept(Book book) throws Exception {
mBookLiveData.setValue(new Response<Book>(Response.CODE_SUCCESS, book));
}
});
}
}
PUBLIC_LIVEDATA 這個是全局緩存數(shù)據(jù),這個由 Respositroy 數(shù)據(jù)層維護(hù)是比較恰當(dāng)?shù)?,mBookLiveData 這個是一次性數(shù)據(jù),這個一次性對應(yīng)的是 BookRespositroy 這個對象的生命周期,MainActivity 通過 viewModule 獲取到這2個 LiveData 管道然后注冊自己的 UI 刷新方法
省略無關(guān)代碼
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private MyViewModule myViewModule;
private ProgressDialog dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化 DataBinding
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
// 使用自定義構(gòu)造器方式創(chuàng)建 ViewModule 對象
MyViewModule.Factroy factroy = new MyViewModule.Factroy(getApplication(), "AAA");
myViewModule = ViewModelProviders.of(this, factroy).get(MyViewModule.class);
// 從 ViewModule 中獲取頁面私有數(shù)據(jù)源的管道,建立聯(lián)系,Response 中包含請求響應(yīng)狀態(tài)碼
myViewModule.getPrivateBookLiveData().observe(this, new Observer<Response<Book>>() {
@Override
public void onChanged(@Nullable Response<Book> response) {
if (response == null) {
return;
}
int code = response.code;
if (code == Response.CODE_LOADING) {
dialog.show();
return;
}
if (code == Response.CODE_SUCCESS) {
dialog.dismiss();
binding.setViewData(response.data.getName());
return;
}
}
});
// 從 ViewModule 中獲取全局公共數(shù)據(jù)源的管道,建立聯(lián)系
BookRespositroy.getPublicLiveData().observe(this, new Observer<Response<Book>>() {
@Override
public void onChanged(@Nullable Response<Book> response) {
if (response == null) {
return;
}
int code = response.code;
if (code == Response.CODE_LOADING) {
dialog.show();
return;
}
if (code == Response.CODE_SUCCESS) {
dialog.dismiss();
binding.setAppData(response.data.getName());
return;
}
}
});
}
最后 MainActivity 通過 viewModule 通知 respositroy 獲取數(shù)據(jù),然后刷新 livedata ,livedata 調(diào)用 setVale 方法就能通知所有注冊其上的對象更新數(shù)據(jù)了。
public void refreshPrivateData() {
mBookLiveData.setValue(new Response<Book>(Response.CODE_LOADING, null));
mBookNetDataSource.getPrivateBook()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Book>() {
@Override
public void accept(Book book) throws Exception {
mBookLiveData.setValue(new Response<Book>(Response.CODE_SUCCESS, book));
}
});
}
注意這里面,loading 的狀態(tài)是由 respositroy 發(fā)送的而不是 viewmodule ,加載狀態(tài)通過 response 中的 code 碼來承載。
核心點:
- 數(shù)據(jù)的流動基于觀察者模式來注冊,數(shù)據(jù)源蹭蹭包裝拋出 LiveData 這個包裹數(shù)據(jù)源的 observable 用于注冊,UI 層獲取 LiveData 注冊 UI 刷新方法,那么整個數(shù)據(jù)通道就正式建立了,這時通知數(shù)據(jù)層加載數(shù)據(jù)就可以了
- 數(shù)據(jù)層中對數(shù)據(jù)源進(jìn)行封裝,對 remote,file,sql,cache 需要分別封裝,具體的數(shù)據(jù)源返回的不是具體的數(shù)據(jù),而是 rxjava 中的 observable ,因為整個數(shù)據(jù)流是基于響應(yīng)式的,要是這里返回個具體數(shù)據(jù)那么思路就不對了,或者用 callback 傳遞給數(shù)據(jù)源都是對響應(yīng)式變成的不理解。
最后
最后想說一下 respositroy 數(shù)據(jù)層的封裝一定要量力而行,我這里 respositroy 層支持持有 net 遠(yuǎn)程數(shù)據(jù)源了,這個一般即使我們的需求了,沒必要過度去封裝,反而不美。但是要是對數(shù)據(jù)游比較多的緩存需求,那么就需要再 respositroy 中封裝一個 DataSource 來管理數(shù)據(jù)源了,比如圖片加載庫,glide 、fresco ,他們都是對數(shù)據(jù)緩存有要讀要起的,你看代碼的代碼思路專門有一個數(shù)據(jù)源管理類對外提供數(shù)據(jù)。
另外若是 respositroy 數(shù)據(jù)層中業(yè)務(wù)處理很復(fù)雜的話,我們可以把具體的業(yè)務(wù)邏輯處理分離成u 一個個的 helper 類,google 源碼中就有很多的 helper 類來輔助管理具體的功能
若是 app 設(shè)計有自己的特殊業(yè)務(wù) code 的話,我們可以把處理放在 respositroy 數(shù)據(jù)層中,在 app 初始化時配置一個靜態(tài)的處理類出來,然后我們在 respositroy 數(shù)據(jù)層中獲取這個處理類來優(yōu)先處理特務(wù)業(yè)務(wù) code ,為啥不放在 respositroy 的基類中,是因為很多 api 我們不需要處理特殊 code ,為了代碼靈活一下犧牲下代碼封裝性。
ps:最后的最后,說一下寫的不好,我的認(rèn)識也淺顯,歡迎大家踴躍噴我,希望通過大家的評論提高進(jìn)步。