Android Architecture Components的應(yīng)用架構(gòu)

Android Architecture Components 是一個(gè)由Google官方推出的庫(kù)脱惰,它能夠幫助你去構(gòu)建一個(gè)健壯搏嗡,易測(cè),可維護(hù)的應(yīng)用拉一。用于管理UI組件生命周期以及處理數(shù)據(jù)持久性等問題采盒。

架構(gòu)原則

應(yīng)用中的關(guān)注點(diǎn)分離。
Activity或Fragment內(nèi)只處理UI相關(guān)邏輯蔚润,任何與此無(wú)關(guān)的代碼都不該堆在其內(nèi)磅氨。
也就是類的單一職責(zé)化。盡可能保持精簡(jiǎn)可以避免許多生命周期相關(guān)的問題嫡纠》匙猓基于用戶交互或其他因素(如低內(nèi)存),Android系統(tǒng)可能隨時(shí)銷毀它們除盏。最好盡量減少對(duì)它們的依賴叉橱,以提供好的用戶體驗(yàn)。
數(shù)據(jù)模型驅(qū)動(dòng) UI
做到數(shù)據(jù)持久化者蠕,這樣至少有兩個(gè)好處:
1.用戶不會(huì)因?yàn)橄到y(tǒng)銷毀我們的應(yīng)用而導(dǎo)致丟失數(shù)據(jù)窃祝。
2.我們的應(yīng)用可以在網(wǎng)絡(luò)狀況不好甚至斷網(wǎng)的情況下繼續(xù)工作。

主要模塊

包含Lifecycles, LiveData, ViewModel, Room, and Paging.
下面主要講解一下Lifecycles,LiveData以及ViewModel

Lifecycles

android.arch.lifecycle 包中提供了可以構(gòu)建生命周期感知的組件的類和接口踱侣,這些組件可以根據(jù) Activity/Fragment 的生命周期自動(dòng)調(diào)整它的行為粪小。

Lifecycle.jpg

從圖中我們可以看到 LifecycleOwner 是 Lifecycle 的持有者大磺,通常是一個(gè) Activity 或 Fragment。想要獲取 Lifecycle 只能通過 LifecycleOwner 的 getLifecycle 方法探膊。Lifecycle 是可觀察的杠愧,它可以持有多個(gè) LifecycleObserver。

  • Lifecycle:它是一個(gè)持有 Activity/Fragment 生命周期狀態(tài)信息的類突想,并且允許其他對(duì)象觀察此狀態(tài)殴蹄。Lifecycle 內(nèi)部維護(hù)了兩個(gè)枚舉,一叫 Event猾担,另一個(gè)叫 State袭灯。Event 是對(duì) Android 組件(Activity 或 Fragment)生命周期函數(shù)的映射,當(dāng) Android Framework 回調(diào)生命周期函數(shù)時(shí)绑嘹,Lifecycle 會(huì)檢查當(dāng)前事件和上一個(gè)事件是否一致稽荧,如果不一致,就根據(jù)當(dāng)前事件計(jì)算出當(dāng)前狀態(tài)工腋,并通知它的觀察者(LifecycleObserver)生命狀態(tài)已經(jīng)發(fā)生變化姨丈。觀察者收到通知后,通過 Lifecycle 提供的 getCurrentSate 方法來獲取剛剛 Lifecycle 計(jì)算出來的當(dāng)前狀態(tài)擅腰,觀察者根據(jù)這個(gè)狀態(tài)來決定要不要執(zhí)行某些操作
    lifecycle-states.png

LifecycleOwner

  • LifecycleOwner:是一個(gè)具有單一方法的接口蟋恬。如果一個(gè)類實(shí)現(xiàn)了此接口,則該類中需要持有一個(gè) Lifecycle 對(duì)象趁冈,并通過LifecycleOwner#getLifecycle() 方法返回該對(duì)象歼争。Support Library 26.1+ 已經(jīng)集成了此組件。

并不是只有 Activity 和 Fragment 才可以實(shí)現(xiàn) LifecycleOwner 接口的渗勘,任何和 Activity/Fragment 生命周期有關(guān)系的類都可以實(shí)現(xiàn)此接口沐绒。通過實(shí)現(xiàn)此接口,該類完全是生命周期可感知的旺坠,只需要對(duì)它進(jìn)行初始化乔遮,它就可以進(jìn)行自己的初始化和清理操作,而不受其 Activity/Fragment 的管理取刃。詳細(xì)可以參看官方文檔說明:LifecycleOwner 實(shí)踐

LifecycleObserver
可以使用 Lifecycle 的類被稱為生命周期感知組件蹋肮。(也就是繼承實(shí)現(xiàn)LifecycleObserver 的類)。

谷歌提倡那些需要和 Android 生命周期協(xié)作的類庫(kù)提供生命周期感知組件璧疗,這樣客戶端代碼就可以很容易集成這些類庫(kù)括尸,而不需要客戶端手動(dòng)管理類庫(kù)中和 Android 生命周期相關(guān)的代碼。

class MyObserver implements LifecycleObserver {
    private boolean enabled = false;
    public MyObserver(Context context, Lifecycle lifecycle, Callback callback) {
       ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void start() {
        if (enabled) {
           // connect
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
            // connect if not connected
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void stop() {
        // disconnect if connected
    }
}

通過注解就可以監(jiān)聽對(duì)應(yīng)的生命周期事件病毡,同時(shí)別忘了調(diào)用 owner.getLifecycle().addObserver() 把觀察者(MyObserver)注冊(cè)到 Lifecycle.

LiveData

LiveData 是一個(gè) observable 數(shù)據(jù)的持有類,和普通的 observable 不同屁柏,LiveData 是生命周期感知的,意味著它代表其它應(yīng)用組件譬如 Activity、Fragment米愿、Service 的生命周期关顷。這確保了 LiveData 只會(huì)更新處于活躍狀態(tài)的組件。

LiveData 通過內(nèi)部類的形式實(shí)現(xiàn)了 LifecycleObserver实愚,它整個(gè)工作流程大概是這樣的:

  1. 將實(shí)現(xiàn)了 LifecycleObserver 的內(nèi)部類注冊(cè)到 owner 的 Lifecycle。
  2. LifecycleObserver 監(jiān)聽了 Lifecycle 所有的生命周期事件
  3. 當(dāng)有生命周期事件發(fā)生時(shí),檢查 Lifecycle 的狀態(tài)是否至少是 STARTED 來判斷 lifecycle 是否處于活躍狀態(tài)
  4. 當(dāng)維護(hù)的值被改變時(shí)阵赠,如果 Lifecycle 處于活躍狀態(tài),通知觀察者(實(shí)現(xiàn)了 android.arch.lifecycle.Observer 接口的對(duì)象)肌稻,否則什么也不做
  5. 當(dāng) Lifecycle 從非活躍狀態(tài)恢復(fù)到活躍狀態(tài)時(shí)清蚀,檢查維護(hù)的值是否在非活躍期間有更新過,如果有爹谭,通知觀察者
  6. 當(dāng) Lifecycle 處于完結(jié)狀態(tài) DESTROYED 時(shí)枷邪,從 Lifecycle 中移除 LifecycleObserver。

很顯然诺凡,LiveData 是響應(yīng)式的东揣,令人驚艷的是,它有效解決了后臺(tái)回調(diào)和 Android 生命周期的上古謎題腹泌。

LiveData 使用起來是這樣的:

public class NameViewModel extends ViewModel {

// Create a LiveData with a String
private MutableLiveData<String> mCurrentName;

    public MutableLiveData<String> getCurrentName() {
        if (mCurrentName == null) {
            mCurrentName = new MutableLiveData<String>();
        }
        return mCurrentName;
    }

// Rest of the ViewModel...
}

現(xiàn)在嘶卧,Activity 可以訪問這個(gè)列表如下:

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

它還提供了 Transformations 來幫助我們轉(zhuǎn)換 LiveData 所持有的數(shù)據(jù)。

Transformations.map()
在LiveData數(shù)據(jù)的改變傳遞到觀察者之前凉袱,在數(shù)據(jù)上應(yīng)用一個(gè)方法:

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});

Transformations.switchMap()
與Transformations.map()類似芥吟,只不過這里傳遞個(gè)switchMap()的方法必須返回一個(gè)LiveData對(duì)象。

private LiveData<User> getUser(String id) {
  ...;
}

LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

ViewModel

看到 ViewModel 這個(gè)詞绑蔫,就會(huì)讓人想起 MVVM运沦,ViewModel 正是 MVVM 架構(gòu)里面的一個(gè)重要角色。

MVVM 按職責(zé)把類分為三種角色配深,分別是 View携添,ViewModel,Model篓叶。ViewModel 正好處于中間烈掠,是連接 View 和 Model 的橋梁。

  • View 只做兩件事情缸托,一件是根據(jù) ViewModel 中存儲(chǔ)的狀態(tài)渲染界面左敌,另外一件是將用戶操作轉(zhuǎn)發(fā)給 ViewModel。用一個(gè)公式來表述是這樣的:view = render(state) + handle(event)俐镐。
  • ViewModel 也只做兩件事矫限。一方面提供 observable properties 給 View 觀察,一方面提供 functions 給 View 調(diào)用,通常會(huì)導(dǎo)致 observable properties 的改變叼风,以及帶來一些額外狀態(tài)取董。observable properties 是指 LiveData、Observable(RxJava) 這種可觀察屬性无宿。View 正是訂閱了這些屬性茵汰,實(shí)現(xiàn)模型驅(qū)動(dòng)視圖。functions 是指可以用來響應(yīng)用戶操作的方法或其它對(duì)象孽鸡,ViewModel 不會(huì)也不應(yīng)該自己處理業(yè)務(wù)蹂午,它通過 functions 把業(yè)務(wù)邏輯的處理委派給 Model。用一個(gè)公式來表述是這樣的:viewmodel = observable properties + functions彬碱。
  • Model 是整個(gè)應(yīng)用的核心豆胸。它包含數(shù)據(jù)以及業(yè)務(wù)邏輯,網(wǎng)絡(luò)訪問堡妒、數(shù)據(jù)持久化都是它的職責(zé)配乱。用一個(gè)公式來表述是這樣的:model = data + state + business logic

在 Android 中皮迟,View 包含 Activity 和 Fragment搬泥,由于 Activity 和 Fragment 可以銷毀后重建,因此要求 ViewModel 在這個(gè)過程中能夠存活下來伏尼,并綁定到新的 Activity 或 Fragment忿檩。架構(gòu)組件提供了 ViewModel 來幫我們實(shí)現(xiàn)這點(diǎn)。

ViewModel的生命周期跟著傳遞給ViewModelProvider的LifeCycle走爆阶,當(dāng)生成了ViewModel的實(shí)例后燥透,它會(huì)一直待在內(nèi)存中,直到對(duì)應(yīng)的LifeCycle徹底結(jié)束辨图。下面是ViewModel與Activity對(duì)應(yīng)的生命周期圖:


viewmodel-lifecycle.png

ViewModel將數(shù)據(jù)從UI中分離出來班套。并且當(dāng)Activity或Fragment重構(gòu)的時(shí)候,ViewModel會(huì)自動(dòng)保留之前的數(shù)據(jù)并給新的Activity或Fragment使用故河。

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

接著在我們的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
        });
    }
}

當(dāng) Activity 或 Fragment 真正 finish 的時(shí)候吱韭,框架會(huì)調(diào)用 ViewModel 中的 onCleared 方法,在這個(gè)方法里面清除不再使用的資源鱼的。

如果 ViewModel需要 Application上下文理盆,例如查找系統(tǒng)服務(wù),則可以擴(kuò)展 AndroidViewModel 該類并在構(gòu)造函數(shù)中接收Application 凑阶。

Fragment之間的數(shù)據(jù)共享
在Activity中包好多個(gè)Fragment并且需要相互通信是非常常見的猿规,這時(shí)就需要這些Fragment定義一些接口,然后讓Activity來進(jìn)行協(xié)調(diào)宙橱。
上面這個(gè)問題可以被ViewModel輕易解決姨俩,假設(shè)有這么一個(gè)Activity蘸拔,它包含F(xiàn)ragmentA和FragmentB,其中A是用戶列表哼勇,B是用戶的詳細(xì)數(shù)據(jù)都伪,點(diǎn)擊列表上的某個(gè)用戶,在B中顯示相應(yīng)的數(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 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.
        });
    }
}

這里要注意的是兩個(gè)Fragment都使用了getActivity作為參數(shù)來獲得ViewModel實(shí)例。這表示這兩個(gè)Fragment獲得的ViewModel對(duì)象是同一個(gè)SharedViewModel猬仁。

使用了ViewModel的好處如下:

Activity不需要做任何事情帝璧,不需要干涉這兩個(gè)Fragment之間的通信。
Fragment不需要互相知道湿刽,即使一個(gè)消失不可見的烁,另一個(gè)也能很好的工作。
Fragment有自己的生命周期诈闺,它們之間互不干擾渴庆,即便你用一個(gè)FragmentC替代了B,F(xiàn)ragmentA也能正常工作雅镊,沒有任何問題襟雷。

參考:
https://developer.android.com/topic/libraries/architecture/guide.html
https://developer.android.com/topic/libraries/architecture/lifecycle.html
https://developer.android.com/topic/libraries/architecture/livedata.html
https://developer.android.com/topic/libraries/architecture/viewmodel.html
https://listenzz.github.io/android-lifecyle-works-perfectly-with-rxjava.html
http://www.cnblogs.com/zqlxtt/p/6888507.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仁烹,隨后出現(xiàn)的幾起案子耸弄,更是在濱河造成了極大的恐慌,老刑警劉巖卓缰,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件计呈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡征唬,警方通過查閱死者的電腦和手機(jī)捌显,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來总寒,“玉大人扶歪,你說我怎么就攤上這事〕ス裕” “怎么了击罪?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)贪薪。 經(jīng)常有香客問我媳禁,道長(zhǎng),這世上最難降的妖魔是什么画切? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任竣稽,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毫别。我一直安慰自己娃弓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布岛宦。 她就那樣靜靜地躺著台丛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砾肺。 梳的紋絲不亂的頭發(fā)上挽霉,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音变汪,去河邊找鬼侠坎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛裙盾,可吹牛的內(nèi)容都是我干的实胸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼番官,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼庐完!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鲤拿,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤假褪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后近顷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體生音,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年窒升,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缀遍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饱须,死狀恐怖域醇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蓉媳,我是刑警寧澤譬挚,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站酪呻,受9級(jí)特大地震影響减宣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜玩荠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一漆腌、第九天 我趴在偏房一處隱蔽的房頂上張望贼邓。 院中可真熱鬧,春花似錦闷尿、人聲如沸塑径。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)统舀。三九已至,卻和暖如春劳景,著一層夾襖步出監(jiān)牢的瞬間绑咱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工枢泰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人铝噩。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓衡蚂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親骏庸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子毛甲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355