理解Android Architecture Components系列之ViewModel(五)

ViewModel設(shè)計(jì)的目的就是存放和處理和UI相關(guān)的數(shù)據(jù)柏肪,并且這些數(shù)據(jù)不受配置變化(Configuration Changes姐刁,例如:旋轉(zhuǎn)屏幕,組件被系統(tǒng)回收)的影響烦味。

由于(Activity/Fragment)會(huì)被系統(tǒng)隨時(shí)銷毀或重新創(chuàng)建聂使,因此,任何存放在這里的數(shù)據(jù)都可能會(huì)丟失谬俄。例如柏靶,Activity中有一個(gè)查詢得到的用戶列表,當(dāng)Activity被重新創(chuàng)建時(shí)溃论,新的Activity需要再次去獲取用戶數(shù)據(jù)宿礁。對(duì)于簡(jiǎn)單的數(shù)據(jù)可以使用 onSaveInstanceState()保存,在onCreate()中恢復(fù)蔬芥。對(duì)于少量的用戶數(shù)據(jù),比如UI狀態(tài)是沒(méi)有問(wèn)題的控汉。但是對(duì)于大量的數(shù)據(jù)笔诵,比如用戶列表,這用做就會(huì)不合適(not suitable)姑子。

另一個(gè)問(wèn)題是乎婿,UI組件會(huì)頻繁的調(diào)用異步回調(diào),這些回調(diào)可能會(huì)非常耗時(shí)街佑。這就需要UI組件管理這些調(diào)用谢翎,并且在UI組件銷毀時(shí)清除這些調(diào)用。這會(huì)花費(fèi)很多的維護(hù)成本,而且當(dāng)UI由于configuration change重新創(chuàng)建時(shí)沐旨,又需要重新調(diào)用森逮,這明顯是一種資源浪費(fèi)(比如網(wǎng)絡(luò)請(qǐng)求)。

最后磁携,還有一個(gè)問(wèn)題就是UI組件需要對(duì)用戶的操作作出響應(yīng)褒侧,并且處理和操作系統(tǒng)的通信。這樣把代碼放在UI組件中會(huì)使這部分代碼變得臃腫,而且對(duì)測(cè)試也不太友好闷供。

ViewModel就是用于解決上述問(wèn)題的烟央。ViewModel用于為UI組件提供數(shù)據(jù),并且能夠在旋轉(zhuǎn)屏幕等Configuration Change發(fā)生時(shí)歪脏,仍能保持里面的數(shù)據(jù)疑俭。當(dāng)UI組件恢復(fù)時(shí),可以立刻向UI提供數(shù)據(jù)婿失。一起看下代碼:

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 async operation to fetch users
    }
}

Activity訪問(wèn)User List數(shù)據(jù):

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

那么問(wèn)題來(lái)了钞艇,假如用戶按返回鍵,主動(dòng)銷毀了這個(gè)Activity呢移怯?這時(shí)系統(tǒng)會(huì)調(diào)用ViewModel的onCleared()方法香璃,清除ViewModel中的數(shù)據(jù)。

在Fragments間分享數(shù)據(jù)

有時(shí)候一個(gè)Activity中的兩個(gè)或多個(gè)Fragment需要分享數(shù)據(jù)或者相互通信舟误,這樣就會(huì)帶來(lái)很多問(wèn)題葡秒,比如數(shù)據(jù)獲取,相互確定生命周期嵌溢。

使用ViewModel可以很好的解決這個(gè)問(wèn)題眯牧。假設(shè)有這樣兩個(gè)Fragment,一個(gè)Fragment提供一個(gè)列表赖草,另一個(gè)Fragment提供點(diǎn)擊每個(gè)item現(xiàn)實(shí)的詳細(xì)信息学少。

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 LifecycleFragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // update UI
        });
    }
}

兩個(gè)Fragment都是通過(guò)getActivity()來(lái)獲取ViewModelProvider。這意味著兩個(gè)Activity都是獲取的屬于同一個(gè)Activity的同一個(gè)ShareViewModel實(shí)例秧骑。
這樣做優(yōu)點(diǎn)如下:

  • Activity不需要寫任何額外的代碼版确,也不需要關(guān)心Fragment之間的通信。
  • Fragment不需要處理除SharedViewModel以外其他的代碼乎折。這兩個(gè)Fragment不需要知道對(duì)方是否存在绒疗。
  • Fragment的生命周期不會(huì)相互影響

ViewModel的生命周期

ViewModel只有在Activity finish或者Fragment detach之后才會(huì)銷毀。下面這張圖顯示了詳細(xì)的生命周期:


viewmodel-lifecycle.png

ViewModel和SavedInstanceState對(duì)比

ViewModel使得在configuration change(旋轉(zhuǎn)屏幕等)保存數(shù)據(jù)變的十分方便骂澄,但是這不能用于應(yīng)用被系統(tǒng)殺死時(shí)持久化數(shù)據(jù)吓蘑。舉個(gè)簡(jiǎn)單的例子,有一個(gè)界面展示國(guó)家信息坟冲。不應(yīng)該把整個(gè)國(guó)家信息放到SavedInstanceState里磨镶,而是把國(guó)家對(duì)應(yīng)的id放到SavedInstanceState,等到界面恢復(fù)時(shí)健提,再通過(guò)id去獲取詳細(xì)的信息琳猫。這些詳細(xì)的信息應(yīng)該被存放在數(shù)據(jù)庫(kù)中。說(shuō)到數(shù)據(jù)庫(kù)私痹,下篇文章將會(huì)介紹Android Architecture Components提供的Room來(lái)操作數(shù)據(jù)庫(kù)沸移。

相關(guān)文章:
理解Android Architecture Components系列(一)
理解Android Architecture Components系列(二)
理解Android Architecture Components系列之Lifecycle(三)
理解Android Architecture Components系列之LiveData(四)
理解Android Architecture Components系列之ViewModel(五)
理解Android Architecture Components系列之Room(六)
理解Android Architecture Components系列之Paging Library(七)
理解Android Architecture Components系列之WorkManager(八)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痪伦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子雹锣,更是在濱河造成了極大的恐慌网沾,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蕊爵,死亡現(xiàn)場(chǎng)離奇詭異辉哥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)攒射,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門醋旦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人会放,你說(shuō)我怎么就攤上這事饲齐。” “怎么了咧最?”我有些...
    開封第一講書人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵捂人,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我矢沿,道長(zhǎng)滥搭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任捣鲸,我火速辦了婚禮瑟匆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘栽惶。我一直安慰自己愁溜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開白布外厂。 她就那樣靜靜地躺著祝谚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酣衷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評(píng)論 1 291
  • 那天次泽,我揣著相機(jī)與錄音穿仪,去河邊找鬼。 笑死意荤,一個(gè)胖子當(dāng)著我的面吹牛啊片,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玖像,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼紫谷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起笤昨,我...
    開封第一講書人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤祖驱,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后瞒窒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捺僻,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年崇裁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了匕坯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拔稳,死狀恐怖葛峻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情巴比,我是刑警寧澤术奖,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站匿辩,受9級(jí)特大地震影響腰耙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铲球,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一挺庞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧稼病,春花似錦选侨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至芍瑞,卻和暖如春晨仑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拆檬。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工洪己, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人竟贯。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓答捕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親屑那。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拱镐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容