摘要:在中是為界置更改后繼續(xù)存在的對(duì)象。由于的特性是對(duì)數(shù)據(jù)進(jìn)行持久化,所以它不能持有與相關(guān)的引用,防止內(nèi)存泄露,因此這里使用與應(yīng)用生命周期綁定的。創(chuàng)建好了,接下來(lái)只剩下在中進(jìn)行使用。得到后,剩下的就是對(duì)數(shù)據(jù)的操作與響應(yīng)。
在Android Architecture Components(AAC)中ViewMode是為界
置更改后繼續(xù)存在的對(duì)象。例如界面的旋轉(zhuǎn)導(dǎo)致界面配置信息改變。
對(duì)于為界面提供數(shù)據(jù),我們所知道的也有其他的一些模式,例如MVP的Presenter與MVVM中的ViewModel。那么我們進(jìn)行一個(gè)假設(shè),如果Activity發(fā)生界面旋轉(zhuǎn),此時(shí)上述的提供數(shù)據(jù)的模式會(huì)發(fā)生什么呢?
對(duì)于Activity的重建,為了提供ui所需的數(shù)據(jù),我們必須重新獲取數(shù)據(jù)(網(wǎng)絡(luò)或者本地?cái)?shù)據(jù)庫(kù)),如果需要保存數(shù)據(jù),也要重新進(jìn)行保存操作。
在對(duì)數(shù)據(jù)進(jìn)行操作時(shí),你必須要處理一些可能造成的內(nèi)存泄露問(wèn)題。
對(duì)于以上問(wèn)題,ViewModel都能夠幫我們解決。只要Activity沒(méi)有徹底被銷(xiāo)毀,使用的都是同一個(gè)ViewModel,同時(shí)對(duì)于它的創(chuàng)建與銷(xiāo)毀我們無(wú)需進(jìn)行維護(hù)管理,能很好的保證資源的釋放。
下面的這張圖能夠幫助我們更好的觀察它在Activity中的生命狀態(tài)
ViewModel貫穿Activity的整個(gè)生命周期,只有當(dāng)Activity徹底釋放時(shí)才會(huì)將其銷(xiāo)毀。所以它能夠更好的幫助我們實(shí)現(xiàn)持久化數(shù)據(jù),防止不必要的數(shù)據(jù)請(qǐng)求,提高App的性能。
是不是有點(diǎn)好奇了呢,下面我們來(lái)簡(jiǎn)單介紹它的使用,為什么說(shuō)簡(jiǎn)單呢?因?yàn)檎娴暮芎?jiǎn)單...依賴(lài)
如果你已經(jīng)有了解過(guò)上篇關(guān)于Lifecycle的文章(Android Architecture Components Part3:Lifecycle),那么可以直接跳過(guò)依賴(lài)部分,沒(méi)有的我們繼續(xù)。
在使用ViewModel之前,我們需要在App或者M(jìn)odule的build.gradle中添加如下代碼
dependencies { def lifecycle_version = "1.1.1" // ViewModel and LiveData implementation "android.arch.lifecycle:extensions:$lifecycle_version" annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" }使用
依賴(lài)已經(jīng)準(zhǔn)備完畢,我們可以直接通過(guò)如下代碼使用
class ContactsViewModel(application: Application, private val defTitle: String = "Contacts") : AndroidViewModel(application) { val message: MutableLiveDataby lazy { MutableLiveData () } val contactsList: MutableLiveData > = MutableLiveData() .... .... fun getContacts(refresh: Boolean): LiveData
> { message.value = "" if (refresh) { getDataFromRemote() } else if (contactsList.value == null || contactsList.value?.size ?: 0 <= 0) { message.value = "數(shù)據(jù)請(qǐng)求中,請(qǐng)稍后!" if (mLocalData.isEmpty()) { getDataFromLocal() } } return contactsList } ... ... }
我們創(chuàng)建ContactsViewModel,讓它繼承于AndroidViewModel,它是對(duì)抽象ViewModel的擴(kuò)展,使用它時(shí)需要傳入Application對(duì)象,方便一些資源的獲取。由于ViewModel的特性是對(duì)數(shù)據(jù)進(jìn)行持久化,所以它不能持有與Activity相關(guān)的引用(Context),防止內(nèi)存泄露,因此這里使用與應(yīng)用生命周期綁定的Application。
在ContactsViewModel中我們結(jié)合MutableLiveData來(lái)更好的管理數(shù)據(jù)的變化更新。
ViewModel創(chuàng)建好了,接下來(lái)只剩下在Activity中進(jìn)行使用。
class ContactsActivity : AppCompatActivity() { private lateinit var mViewModel: ContactsViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_contacts_layout) setupViewModel() } private fun setupViewModel() { mViewModel = ViewModelProviders.of(this)[ContactsViewModel::class.java] //active STARTED、RESUMED mViewModel.getContacts(true).observe(this, Observer { //todo ... }) mViewModel.message.observe(this, Observer { //todo ... }) } }
實(shí)際上我們只需一行代碼就可以獲取到ViewModel的實(shí)例,通過(guò)ViewModelProviders.of()方法傳入Activity對(duì)象,它會(huì)返回一個(gè)ViewModelProvider對(duì)象,然后我們?cè)偈褂盟?strong>get()來(lái)根據(jù)不同的ViewModel的Class對(duì)象來(lái)獲取到相應(yīng)的ViewModel實(shí)例。
只要Activity對(duì)象沒(méi)有改變,同時(shí)都是同一個(gè)ViewModel的Class對(duì)象,那么我們無(wú)論何時(shí)獲取的都是同一個(gè)ViewModel實(shí)例。這就實(shí)現(xiàn)了在Activity中的ViewModel持久化特性。由于ViewModel是同一個(gè),自然它里面的數(shù)據(jù)也是同一份。
得到ViewModel后,剩下的就是對(duì)數(shù)據(jù)的操作與響應(yīng)。這里結(jié)合了LiveData所以方便了許多。
LiveData之間已經(jīng)有詳細(xì)介紹,如需了解可以查看文章末的鏈接。ViewModelProvider
到這里我想你心中可能會(huì)有如下幾個(gè)疑問(wèn)
ViewModel它是如何初始化的,對(duì)象是如何實(shí)例化的
如何向ViewModel中傳遞初始化的參數(shù)
這兩個(gè)疑問(wèn)都將由ViewModelProvider來(lái)解決。
我們回到獲取ViewModelProvider的ViewModelProviders.of()方法,進(jìn)入源碼查看。
@NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { Application application = checkApplication(activity); if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application); } return new ViewModelProvider(ViewModelStores.of(activity), factory); }
我們也沒(méi)有發(fā)現(xiàn)我們想要的代碼,但我們發(fā)現(xiàn)factory。我們?cè)讷@取ViewModel時(shí)并沒(méi)有傳入factory,所以它會(huì)走空判斷里面的代碼,創(chuàng)建一個(gè)默認(rèn)的factory。那么我們?cè)龠M(jìn)入ViewModelProvider中查看靜態(tài)內(nèi)部類(lèi)AndroidViewModelFactory
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory { ... ... @NonNull @Override publicT create(@NonNull Class modelClass) { if (AndroidViewModel.class.isAssignableFrom(modelClass)) { //noinspection TryWithIdenticalCatches try { return modelClass.getConstructor(Application.class).newInstance(mApplication); } catch (NoSuchMethodException e) { throw new RuntimeException("Cannot create an instance of " + modelClass, e); } catch (IllegalAccessException e) { throw new RuntimeException("Cannot create an instance of " + modelClass, e); } catch (InstantiationException e) { throw new RuntimeException("Cannot create an instance of " + modelClass, e); } catch (InvocationTargetException e) { throw new RuntimeException("Cannot create an instance of " + modelClass, e); } } return super.create(modelClass); } }
我們只看關(guān)鍵代碼,它繼承于NewInstanceFactory,其中只有一個(gè)方法create()。AndroidViewModelFactory重新實(shí)現(xiàn)了create(),在重寫(xiě)的方法中我們找到了我們想要的方法調(diào)用。在這里它通過(guò)Class的getConstructor()方法獲取匹配的Constructor對(duì)象,然后再通過(guò)newInstance()方法來(lái)獲取匹配的對(duì)象實(shí)例。這樣我們所需要的ViewModel實(shí)例就創(chuàng)建了,第一個(gè)疑問(wèn)就此解決。
至于第二個(gè)疑問(wèn),細(xì)心的話不難發(fā)現(xiàn),上面在調(diào)用newInstance()方法時(shí)已經(jīng)傳了一個(gè)初始化的參數(shù)mApplication。所以如果我們要再傳入其它自定義的初始化參數(shù),只需實(shí)現(xiàn)我們自己的create()方法。要自定義create()方法,我們就要自定義一個(gè)factory,繼承NewInstanceFactory類(lèi)。
下面是實(shí)現(xiàn)ContactsViewModel在初始化時(shí)傳入特定的title值
class ContactsFactory(private val application: Application) : ViewModelProvider.NewInstanceFactory() { companion object { @SuppressLint("StaticFieldLeak") private var instance: ContactsFactory? = null fun getInstance(application: Application): ContactsFactory { if (instance == null) { instance = ContactsFactory(application) } return instance as ContactsFactory } } override funcreate(modelClass: Class ): T { if (modelClass.isAssignableFrom(ContactsViewModel::class.java)) { return ContactsViewModel(application, "Factory Contacts") as T } return super.create(modelClass) } }
重點(diǎn)自然是create()方法,通過(guò)isAssignableFrom()方法判斷需要實(shí)例化的類(lèi)型,由于我們能夠明確到具體的類(lèi),所以可以直接使用正常的類(lèi)實(shí)例化操作。已經(jīng)有了factory,最后在獲取ViewModel時(shí)傳入即可
mViewModel = ViewModelProviders.of(this, ContactsFactory.getInstance(application))[ContactsViewModel::class.java]
ViewModel就是這么簡(jiǎn)單,但它對(duì)數(shù)據(jù)的持久化卻異常突出。是否已經(jīng)迫不及待了呢?趕緊來(lái)試試它的特性吧。
總結(jié)最后Android Architecture Components(AAC)系列到此就告一段落了,讓我們來(lái)回顧一下AAC。我們通過(guò)Room可以快速方便的實(shí)現(xiàn)本地?cái)?shù)據(jù)存儲(chǔ);結(jié)合LiveData來(lái)觀測(cè)數(shù)據(jù)的更新變化與及時(shí)反映到UI層;同時(shí)使用Lifecycle來(lái)讓我們的組件或數(shù)據(jù)容器的具備生命感知能力,幫助我們的減少生命狀態(tài)的處理與異常錯(cuò)誤的發(fā)生;最后將界面數(shù)據(jù)存儲(chǔ)到ViewModel中,使得數(shù)據(jù)達(dá)到持久化,減少不必要的數(shù)據(jù)請(qǐng)求與資源消耗。
下面的能夠初步體現(xiàn)使用AAC后的App項(xiàng)目架構(gòu)形態(tài)
最后感謝大家對(duì)AAC架構(gòu)系列的支持!如果感覺(jué)不錯(cuò)的話,可以幫忙點(diǎn)贊收藏一下或者關(guān)注我的公眾號(hào)。同時(shí)文章中的代碼都可以在Github中獲取到。使用時(shí)請(qǐng)將分支切換到feat_architecture_components
相關(guān)文章Android Architecture Components Part1:Room
Android Architecture Components Part2:LiveData
Android Architecture Components Part3:Lifecycle
私人博客
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/11893.html
摘要:例如,在方面它主要能夠幫助你解決以下兩個(gè)問(wèn)題在主線程中執(zhí)行耗時(shí)任務(wù)導(dǎo)致的主線程阻塞,從而使發(fā)生。提供主線程安全,同時(shí)對(duì)來(lái)自于主線程的網(wǎng)絡(luò)回調(diào)磁盤(pán)操提供保障。在線程通過(guò)從數(shù)據(jù)庫(kù)取數(shù)據(jù),一旦數(shù)據(jù)返回,在主線程進(jìn)行處理。 showImg(https://segmentfault.com/img/bVbuqpM?w=800&h=320); 今天我們來(lái)聊聊Kotlin Coroutine,如果你...
摘要:目前它還未正式發(fā)布。理解系列一是谷歌在發(fā)布一套幫助開(kāi)發(fā)者解決架構(gòu)設(shè)計(jì)的方案。但最近還是推出了一份關(guān)于應(yīng)用架構(gòu)的實(shí)踐指南,并給出了相當(dāng)詳盡的步驟和一些指導(dǎo)建議。 MVP+Retrofit+Rxjava在項(xiàng)目中實(shí)戰(zhàn)解析 文章目標(biāo) MVP在android中的原理解析 MVP+Retrofit+Rxjava在項(xiàng)目中實(shí)戰(zhàn)解析 架構(gòu)經(jīng)驗(yàn)分享 MVP簡(jiǎn)單介紹 先說(shuō)說(shuō)MVC分層: View:對(duì)應(yīng)于布局...
閱讀 2501·2023-04-26 00:01
閱讀 864·2021-10-27 14:13
閱讀 1917·2021-09-02 15:11
閱讀 3457·2019-08-29 12:52
閱讀 592·2019-08-26 12:00
閱讀 2627·2019-08-26 10:57
閱讀 3468·2019-08-26 10:32
閱讀 2903·2019-08-23 18:29