成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Android Architecture Components Part4:ViewModel

Cympros / 578人閱讀

摘要:在中是為界置更改后繼續(xù)存在的對象。由于的特性是對數(shù)據(jù)進(jìn)行持久化,所以它不能持有與相關(guān)的引用,防止內(nèi)存泄露,因此這里使用與應(yīng)用生命周期綁定的。創(chuàng)建好了,接下來只剩下在中進(jìn)行使用。得到后,剩下的就是對數(shù)據(jù)的操作與響應(yīng)。

在Android Architecture Components(AAC)中ViewMode是為界
置更改后繼續(xù)存在的對象。例如界面的旋轉(zhuǎn)導(dǎo)致界面配置信息改變。

對于為界面提供數(shù)據(jù),我們所知道的也有其他的一些模式,例如MVP的Presenter與MVVM中的ViewModel。那么我們進(jìn)行一個假設(shè),如果Activity發(fā)生界面旋轉(zhuǎn),此時上述的提供數(shù)據(jù)的模式會發(fā)生什么呢?

對于Activity的重建,為了提供ui所需的數(shù)據(jù),我們必須重新獲取數(shù)據(jù)(網(wǎng)絡(luò)或者本地數(shù)據(jù)庫),如果需要保存數(shù)據(jù),也要重新進(jìn)行保存操作。

在對數(shù)據(jù)進(jìn)行操作時,你必須要處理一些可能造成的內(nèi)存泄露問題。

對于以上問題,ViewModel都能夠幫我們解決。只要Activity沒有徹底被銷毀,使用的都是同一個ViewModel,同時對于它的創(chuàng)建與銷毀我們無需進(jìn)行維護(hù)管理,能很好的保證資源的釋放。

下面的這張圖能夠幫助我們更好的觀察它在Activity中的生命狀態(tài)

ViewModel貫穿Activity的整個生命周期,只有當(dāng)Activity徹底釋放時才會將其銷毀。所以它能夠更好的幫助我們實(shí)現(xiàn)持久化數(shù)據(jù),防止不必要的數(shù)據(jù)請求,提高App的性能。

是不是有點(diǎn)好奇了呢,下面我們來簡單介紹它的使用,為什么說簡單呢?因?yàn)檎娴暮芎唵?..
依賴

如果你已經(jīng)有了解過上篇關(guān)于Lifecycle的文章(Android Architecture Components Part3:Lifecycle),那么可以直接跳過依賴部分,沒有的我們繼續(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"
}
使用

依賴已經(jīng)準(zhǔn)備完畢,我們可以直接通過如下代碼使用

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ù)請求中,請稍后!"
            if (mLocalData.isEmpty()) {
                getDataFromLocal()
            }
        }
        return contactsList
    }
    ...
    ...
}

我們創(chuàng)建ContactsViewModel,讓它繼承于AndroidViewModel,它是對抽象ViewModel的擴(kuò)展,使用它時需要傳入Application對象,方便一些資源的獲取。由于ViewModel的特性是對數(shù)據(jù)進(jìn)行持久化,所以它不能持有與Activity相關(guān)的引用(Context),防止內(nèi)存泄露,因此這里使用與應(yīng)用生命周期綁定的Application。

在ContactsViewModel中我們結(jié)合MutableLiveData來更好的管理數(shù)據(jù)的變化更新。

ViewModel創(chuàng)建好了,接下來只剩下在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í)例,通過ViewModelProviders.of()方法傳入Activity對象,它會返回一個ViewModelProvider對象,然后我們再使用它的get()來根據(jù)不同的ViewModel的Class對象來獲取到相應(yīng)的ViewModel實(shí)例。

只要Activity對象沒有改變,同時都是同一個ViewModel的Class對象,那么我們無論何時獲取的都是同一個ViewModel實(shí)例。這就實(shí)現(xiàn)了在Activity中的ViewModel持久化特性。由于ViewModel是同一個,自然它里面的數(shù)據(jù)也是同一份。

得到ViewModel后,剩下的就是對數(shù)據(jù)的操作與響應(yīng)。這里結(jié)合了LiveData所以方便了許多。

LiveData之間已經(jīng)有詳細(xì)介紹,如需了解可以查看文章末的鏈接。
ViewModelProvider

到這里我想你心中可能會有如下幾個疑問

ViewModel它是如何初始化的,對象是如何實(shí)例化的

如何向ViewModel中傳遞初始化的參數(shù)

這兩個疑問都將由ViewModelProvider來解決。

我們回到獲取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);
    }

我們也沒有發(fā)現(xiàn)我們想要的代碼,但我們發(fā)現(xiàn)factory。我們在獲取ViewModel時并沒有傳入factory,所以它會走空判斷里面的代碼,創(chuàng)建一個默認(rèn)的factory。那么我們再進(jìn)入ViewModelProvider中查看靜態(tài)內(nè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,其中只有一個方法create()。AndroidViewModelFactory重新實(shí)現(xiàn)了create(),在重寫的方法中我們找到了我們想要的方法調(diào)用。在這里它通過Class的getConstructor()方法獲取匹配的Constructor對象,然后再通過newInstance()方法來獲取匹配的對象實(shí)例。這樣我們所需要的ViewModel實(shí)例就創(chuàng)建了,第一個疑問就此解決。

至于第二個疑問,細(xì)心的話不難發(fā)現(xiàn),上面在調(diào)用newInstance()方法時已經(jīng)傳了一個初始化的參數(shù)mApplication。所以如果我們要再傳入其它自定義的初始化參數(shù),只需實(shí)現(xiàn)我們自己的create()方法。要自定義create()方法,我們就要自定義一個factory,繼承NewInstanceFactory類。

下面是實(shí)現(xiàn)ContactsViewModel在初始化時傳入特定的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()方法,通過isAssignableFrom()方法判斷需要實(shí)例化的類型,由于我們能夠明確到具體的類,所以可以直接使用正常的類實(shí)例化操作。已經(jīng)有了factory,最后在獲取ViewModel時傳入即可

mViewModel = ViewModelProviders.of(this, ContactsFactory.getInstance(application))[ContactsViewModel::class.java]

ViewModel就是這么簡單,但它對數(shù)據(jù)的持久化卻異常突出。是否已經(jīng)迫不及待了呢?趕緊來試試它的特性吧。

總結(jié)

最后Android Architecture Components(AAC)系列到此就告一段落了,讓我們來回顧一下AAC。我們通過Room可以快速方便的實(shí)現(xiàn)本地數(shù)據(jù)存儲;結(jié)合LiveData來觀測數(shù)據(jù)的更新變化與及時反映到UI層;同時使用Lifecycle來讓我們的組件或數(shù)據(jù)容器的具備生命感知能力,幫助我們的減少生命狀態(tài)的處理與異常錯誤的發(fā)生;最后將界面數(shù)據(jù)存儲到ViewModel中,使得數(shù)據(jù)達(dá)到持久化,減少不必要的數(shù)據(jù)請求與資源消耗。

下面的能夠初步體現(xiàn)使用AAC后的App項(xiàng)目架構(gòu)形態(tài)

最后感謝大家對AAC架構(gòu)系列的支持!如果感覺不錯的話,可以幫忙點(diǎn)贊收藏一下或者關(guān)注我的公眾號。同時文章中的代碼都可以在Github中獲取到。使用時請將分支切換到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)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/11893.html

相關(guān)文章

  • What? 你還不知道Kotlin Coroutine?

    摘要:例如,在方面它主要能夠幫助你解決以下兩個問題在主線程中執(zhí)行耗時任務(wù)導(dǎo)致的主線程阻塞,從而使發(fā)生。提供主線程安全,同時對來自于主線程的網(wǎng)絡(luò)回調(diào)磁盤操提供保障。在線程通過從數(shù)據(jù)庫取數(shù)據(jù),一旦數(shù)據(jù)返回,在主線程進(jìn)行處理。 showImg(https://segmentfault.com/img/bVbuqpM?w=800&h=320); 今天我們來聊聊Kotlin Coroutine,如果你...

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

    摘要:目前它還未正式發(fā)布。理解系列一是谷歌在發(fā)布一套幫助開發(fā)者解決架構(gòu)設(shè)計的方案。但最近還是推出了一份關(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簡單介紹 先說說MVC分層: View:對應(yīng)于布局...

    bergwhite 評論0 收藏0

發(fā)表評論

0條評論

Cympros

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<