只需跟著Google學(xué)android:ViewModel篇

前言

系列文章:
只需跟著Google學(xué)android:ViewModel篇

關(guān)于ViewModel的內(nèi)容猎莲,大概半年前已經(jīng)寫過兩篇內(nèi)容(但是建議看官方文檔):

官方文檔:ViewModel

上述官方文檔:ViewModel地址:https://developer.android.com/topic/libraries/architecture/viewmodel
我之前的文章:一點(diǎn)點(diǎn)入坑JetPack:ViewModel篇

官方文檔:Saved State module for ViewModel

上述官方文檔:Saved State module for ViewModel地址:https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate
我之前的文章:ViewModel的局限,銷毀重建的方案SavedStateHandle

之前寫的文章現(xiàn)在來看也是沒啥毛病,ViewModel該聊的基本也都聊到了寂屏。因此今天這篇文章更多的是對之前文章的補(bǔ)充

  • ViewModel存在的意義
  • Android-KTX對ViewModel的增強(qiáng)
  • ViewModel的錯誤用法

正文

官方對ViewModel的定義:

  • 1专酗、類職責(zé):負(fù)責(zé)為界面準(zhǔn)備數(shù)據(jù)(意味著一切處理數(shù)據(jù)邏輯的業(yè)務(wù)代碼,應(yīng)該寫在ViewModel中)
  • 2机隙、在配置更改期間會自動保留ViewModel對象:因此可以作為跨頁面(Fragment)通訊的基石
image.png

接下來我們進(jìn)一步深究一下這倆個定義:

一纽谒、ViewModel的意義

Model/View/ViewModel(MVVM)模型中往史,ViewModel層是這樣的定義:

上述Model/View/ViewModel(MVVM)模型鏈接地址:https://docs.microsoft.com/zh-cn/archive/blogs/johngossman/introduction-to-modelviewviewmodel-pattern-for-building-wpf-apps

只有一小部分View層控件可以直接與Model層進(jìn)行數(shù)據(jù)綁定,尤其是在Model層是開發(fā)人員無法控制的情況下(由其他人提供)佛舱。該Model層提供的數(shù)據(jù)很可能是無法直接映射到控件上椎例。 此外UI控件可能需要執(zhí)行復(fù)雜的操作,而這些代碼寫在View層中沒有意義(因?yàn)樗鼈儾粚儆赨I控件的邏輯)请祖,并且這些操作邏輯太過具體订歪,也無法包含在Model層中(因?yàn)檫@也不是Model層應(yīng)該關(guān)心的) 。 所以肆捕,我們需要一個處理View層狀態(tài)的地方刷晋。

ViewModel層就是負(fù)責(zé)這些任務(wù)。ViewModel層包含將Model層數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為View層數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)轉(zhuǎn)換器慎陵,并且包含View層可用于與Model層進(jìn)行交互的命令眼虱。

由上述定義,我們可以清晰的明確:ViewModel層是轉(zhuǎn)換層席纽。用于把Model層的輸出數(shù)據(jù)轉(zhuǎn)換成View層使用的輸入數(shù)據(jù)捏悬,把View層的輸出數(shù)據(jù)轉(zhuǎn)換成Model層使用的輸入數(shù)據(jù)

image.png

咱們會發(fā)現(xiàn)MVVM中ViewModel的定義润梯,和Google推出的ViewModel庫的第一個職責(zé)定義很類似过牙。

因此,可以順其自然使用ViewModel來作為MVVM中ViewModel層的實(shí)現(xiàn)方案纺铭。既然使用ViewModel作為ViewModel層寇钉,那么它的一大意圖也就明確了:規(guī)范我們的代碼組織結(jié)構(gòu),告訴我們處理數(shù)據(jù)數(shù)據(jù)的代碼應(yīng)該寫在ViewModel中舶赔。

明確了第一大意圖扫倡,咱們再看一看上述第二大意圖:在配置更新期間,保存ViewModel實(shí)例竟纳。

短短的幾個字撵溃,有2個很重要的信息:

  • 1、ViewModel實(shí)例的生命周期對Activity/Fragment長蚁袭。
  • 2征懈、ViewModel不能處理Activity銷毀重建的情況。

第一個信息意味著我們不能這么干:

image.png

如果需要context揩悄,可以使用AndroidViewModel

第二個信息如何處理?詳見ViewModel的局限鬼悠,銷毀重建的方案SavedStateHandle

二删性、Android-KTX

引用官方的一句話解釋一下什么叫KTX:

Android KTX 是包含在 Android Jetpack 及其他 Android 庫中的一組Kotlin 擴(kuò)展程序亏娜。

KTX 擴(kuò)展程序可以為 Jetpack、Android平臺及其他API提供簡潔的慣用Kotlin代碼蹬挺。為此维贺,這些擴(kuò)展程序利用了多種 Kotlin 語言功能,其中包括:

  • 擴(kuò)展函數(shù)
  • 擴(kuò)展屬性
  • Lambda
  • 命名參數(shù)
  • 參數(shù)默認(rèn)值
  • 協(xié)程

KTX有很多巴帮,有興趣了解其他KTX的內(nèi)容溯泣,可以訪問官網(wǎng)

上述官網(wǎng)地址:https://developer.android.google.cn/kotlin/ktx?hl=zh_cn#viewmodel

2.1榕茧、Fragment-KTX為我們提供了什么垃沦?

日常我們獲取到ViewModel實(shí)例時,大概是這個樣子:

lateinit var viewModel: XXViewModel

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    viewModel = ViewModelProviders.of(this)[XXViewModel::class.java]
}

使用帶SavedStateHandle還要這樣:

lateinit var viewModel: XXViewModel

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    viewModel = ViewModelProvider(
        this,
        SavedStateViewModelFactory(Application, this)
    )[XXViewModel::class.java]
}

巨麻煩用押,而且這都是樣本代碼肢簿。如果我們引入Fragment-KTX:

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.2.4"
}

上述倆種初始化ViewModel的方式,可以簡化為一個by關(guān)鍵字

// Fragment級別的ViewModel
private val viewModel: XXViewModel by viewModels()
// Activity級別的ViewModel
private val viewModel: XXViewModel by activityViewModels()

2.2蜻拨、ViewModel-KTX為我們提供了什么池充?

給我們提供了一協(xié)程環(huán)境viewModelScope,因此在ViewModel中缎讼,如果我們想要使用協(xié)程收夸,可以直接:

viewModelScope.launch  {
    // ...
}

而且也不用擔(dān)心Job是否被cancel掉。

注意血崭,協(xié)程是協(xié)作式的咱圆。不是說調(diào)了Job.canel()就萬事大吉了,我們還需要在對應(yīng)的launch中顯示的基于isActive去判斷當(dāng)前的協(xié)程是否存活(協(xié)程部分有機(jī)會再展開)功氨。

三序苏、ViewModel的錯誤用法

聊完上述部分,我們再聊一聊錯誤或者是有坑的點(diǎn)捷凄。

3.1忱详、AndroidViewModel中慎重進(jìn)行R.string.xxx

先上一段代碼:

public class MyViewModel extends AndroidViewModel {
    public final MutableLiveData<String> statusLabel = new MutableLiveData<>();
    
    public SampleViewModel(Application context) {
        super(context);
        statusLabel.setValue(context.getString(R.string.labelString));
    }
}

這種用法的問題在于,ViewModel在配置更新的時候跺涤,并不會銷毀重建因此構(gòu)造函數(shù)不會重走匈睁。

因此如果此時需要動態(tài)替換R.string.labelString,那么這種情況下是不正確的桶错。

因此在ViewModel里動態(tài)加載string航唆,是有坑的需要慎重院刁。

3.2糯钙、ViewModel不能解決銷毀重建問題

銷毀重建,這個問題八成沒有人注意,但是一旦遇到這個問題,基本上是“致命”的任岸。

上述銷毀重建地址:https://developer.android.com/topic/libraries/architecture/saving-states#use_onsaveinstancestate_as_backup_to_handle_system-initiated_process_death

不知道大家日常有沒有處理過:“一定”不為null的情況下再榄,出現(xiàn)了空指針的crash。這種case歸咎于銷毀重建基本跑不了享潜。

復(fù)現(xiàn)銷毀重建的場景很簡單困鸥,在開發(fā)者選項(xiàng)中,開啟:不保留活動剑按。

因此疾就,在ViewModel中存儲成員變量、Callback等行為艺蝴。在銷毀重建的場景下都是很危險(xiǎn)的猬腰。那針對這種情況該怎么辦?

  • 成員變量(如果業(yè)務(wù)場景不在意銷毀重建吴趴,可以無視漆诽。如果不能無視,回頭瞅一下開篇的文章锣枝。)
  • Callback(下一篇LiveData篇厢拭,會結(jié)合Google的文章,展開一段合理的處理CallBack的方案)

尾聲

關(guān)于ViewModel的內(nèi)容撇叁,想聊的就這么多啦供鸠。

上述的內(nèi)容主要從兩個架構(gòu)和“”的角度展開,更多的是想輸出一種思路(希望各位同學(xué)能夠接受)陨闹,先從官方文檔中思考技術(shù)出現(xiàn)的意義楞捂。有了這個基礎(chǔ)再看其他的網(wǎng)文,就可以取其精華去其糟粕趋厉。

個人公眾號:咸魚正翻身
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末寨闹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子君账,更是在濱河造成了極大的恐慌繁堡,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乡数,死亡現(xiàn)場離奇詭異椭蹄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)净赴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進(jìn)店門绳矩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人玖翅,你說我怎么就攤上這事翼馆「钜裕” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵写妥,是天一觀的道長拳球。 經(jīng)常有香客問我审姓,道長珍特,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任魔吐,我火速辦了婚禮扎筒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酬姆。我一直安慰自己嗜桌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布辞色。 她就那樣靜靜地躺著骨宠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪相满。 梳的紋絲不亂的頭發(fā)上层亿,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機(jī)與錄音立美,去河邊找鬼匿又。 笑死,一個胖子當(dāng)著我的面吹牛建蹄,可吹牛的內(nèi)容都是我干的碌更。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼洞慎,長吁一口氣:“原來是場噩夢啊……” “哼痛单!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起劲腿,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤旭绒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谆棱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體快压,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年垃瞧,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔫劣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡个从,死狀恐怖脉幢,靈堂內(nèi)的尸體忽然破棺而出歪沃,到底是詐尸還是另有隱情,我是刑警寧澤嫌松,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布沪曙,位于F島的核電站,受9級特大地震影響萎羔,放射性物質(zhì)發(fā)生泄漏液走。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一贾陷、第九天 我趴在偏房一處隱蔽的房頂上張望缘眶。 院中可真熱鬧,春花似錦髓废、人聲如沸巷懈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽顶燕。三九已至,卻和暖如春冈爹,著一層夾襖步出監(jiān)牢的瞬間涌攻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工犯助, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留癣漆,地道東北人。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓剂买,卻偏偏與公主長得像惠爽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瞬哼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評論 2 355