亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

Android Architecture Components Part4:ViewModel

Cympros / 627人閱讀

摘要:在中是為界置更改后繼續(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: MutableLiveData by 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
        public  T 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 fun  create(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

關(guān)注

私人博客

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/11893.html

相關(guān)文章

  • What? 你還不知道Kotlin Coroutine?

    摘要:例如,在方面它主要能夠幫助你解決以下兩個(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,如果你...

    yunhao 評(píng)論0 收藏0
  • Android架構(gòu)

    摘要:目前它還未正式發(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)于布局...

    bergwhite 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

Cympros

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<