欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

源碼解析Android Jetpack組件之ViewModel的使用

 更新時(shí)間:2023年04月21日 15:27:30   作者:孫先森Blog  
Jetpack 是一個(gè)豐富的組件庫(kù),它的組件庫(kù)按類別分為 4 類,分別是架構(gòu)(Architecture)、界面(UI)、 行為(behavior)和基礎(chǔ)(foundation)。本文將從源碼和大家講講Jetpack組件中ViewModel的使用

前言

在之前 LiveData 源碼淺析的博客中提到了 ViewModel 組件,當(dāng)時(shí)對(duì) ViewModel 的解釋是 “生命周期比Activity” 更長(zhǎng)的對(duì)象。本文就來(lái)了解下其實(shí)現(xiàn)原理。

依賴版本

// 注意這里的 appcompat、activity-ktx、fragment-ktx
// 高版本的自動(dòng)引入了 viewmodel-savedstate 實(shí)戰(zhàn)中很少用到的功能
// 篇幅原因 就不再本文中分析 viewmodel-savedstate 擴(kuò)展組件了
implementation 'androidx.appcompat:appcompat:1.0.0'

def fragment_version = "1.1.0"
def activity_version = "1.0.0"
implementation "androidx.activity:activity-ktx:$activity_version"
implementation "androidx.fragment:fragment-ktx:$fragment_version"

def lifecycle_version = "2.5.1"

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"

基礎(chǔ)使用

定義

class MainViewModel: ViewModel(){ ... }
// or 
class MainViewModel(application: Application): AndroidViewModel(application){
    val data: String = ""
    
    fun requestData(){
        data = "xxx"
    }
}

在 MainVieModel 中可以定義 UI 界面中需要的數(shù)據(jù)(對(duì)象、LiveData、Flow 等等)和方法,在 Activity 真正銷毀前 ViewModel 中的數(shù)據(jù)不會(huì)丟失。

Activity 中獲取

val vm = ViewModelProvider(this).get(MainViewModel::class.java)
// or
// 引入 activity-ktx 庫(kù)可以這樣初始化 ViewModel
val vm by viewModels<MainViewModel>()

// 通過(guò) vm 可以調(diào)用其中的方法、獲取其中的數(shù)據(jù)
vm.requestData()
Log.e(TAG, vm.data)

Fragment 中獲取

val vm = ViewModelProvider(this).get(MainViewModel::class.java)
// or 
// 獲取和 Activity 共享的 ViewModel 也就是同一個(gè) ViewModel 對(duì)象
val vm = ViewModelProvider(requireActivity()).get(MainViewModel::class.java)

引入 fragment-ktx 可以這樣初始化

val vm = viewModels<MainViewModel>()
// or 效果同上
val vm = activityViewModels<MainViewModel>()

前置知識(shí)

ViewModel 的使用非常簡(jiǎn)單,也很容易理解,就是一個(gè)生命周期長(zhǎng)于 Activity 的對(duì)象,區(qū)別在于不會(huì)造成內(nèi)存泄漏。ViewModel 不是魔法,站在開發(fā)者的角度在 ViewModel 沒(méi)有問(wèn)世之前橫豎屏切換需要保存狀態(tài)數(shù)據(jù)的需求通常都是通過(guò) onSaveInstanceState、onRestoreInstanceState 來(lái)實(shí)現(xiàn)。

onSaveInstanceState、onRestoreInstanceState

關(guān)于這兩個(gè)方法這里就簡(jiǎn)單概述一下:onSaveInstanceState 用于在 Activity 橫豎屏切換(意外銷毀)前保存數(shù)據(jù),而 onRestoreInstanceState 是用于 Activity 橫豎屏切換(重建)后獲取保存的數(shù)據(jù);

onSaveInstanceState 調(diào)用流程

由于是在 Activity 銷毀前觸發(fā),那么直接來(lái) ActivityThread 中找到 performPauseActivity 方法:

ActivityThread.java

private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason, PendingTransactionActions pendingActions) {
    // ...
    if (shouldSaveState) {
        callActivityOnSaveInstanceState(r);
    }
    // ...
}

private void callActivityOnSaveInstanceState(ActivityClientRecord r) {
    // ...
    // 這里通過(guò) ActivityClientRecord 獲取到 activity
    // state 是 Bundle 對(duì)象,后面要保存的數(shù)據(jù)就放在 state 中
    mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
    // ...
}

這里有 ActivityThread 調(diào)用到了 Instrumentation 中,繼續(xù)看源碼:

Instrumentation.java

public void callActivityOnSaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
    activity.performSaveInstanceState(outState);
}

根據(jù)傳入的 activity 調(diào)用其 performSaveInstanceState 方法:

Activity.java

final void performSaveInstanceState(@NonNull Bundle outState) {
    onSaveInstanceState(outState);
}

總結(jié)一下,onSaveInstanceState 中我們將數(shù)據(jù)存儲(chǔ)在 Bundle 對(duì)象中,而這個(gè) Bundle 對(duì)象是存儲(chǔ)在 ActivityClientRecord 中。

onRestoreInstanceState 調(diào)用流程

看完了 onSaveInstanceState 的調(diào)用流程,那么 onRestoreInstanceState 的流程就來(lái)簡(jiǎn)單說(shuō)說(shuō),由于在 onStart 后發(fā)生回調(diào),所以直接去看 ActivityThread 中的源碼:

ActivityThread.java

public void handleStartActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, ActivityOptions activityOptions) {
    // ...
    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
    // ...
}

可以看出這里從 ActivityClientRecord 中取出了 activity 和 state 進(jìn)行傳毒,后面就和 onSaveInstanceState 調(diào)用流程一樣了,源碼比較簡(jiǎn)單就不貼了。

onRetainCustomNonConfigurationInstance、getLastCustomNonConfigurationInstance

除了 onSaveInstanceState 和 onRestoreInstanceState,在 Activity 中還有一組方法可以實(shí)現(xiàn)類似的功能,就是 onRetainCustomNonConfigurationInstance 和 getLastCustomNonConfigurationInstance,前者即保存數(shù)據(jù),后者即獲取保存的數(shù)據(jù);

簡(jiǎn)單使用

override fun onRetainCustomNonConfigurationInstance(): Any? {
    val data = SaveStateData()
    return data
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 獲取保存的數(shù)據(jù)
    val data = getLastCustomNonConfigurationInstance() as SaveStateData
}

和 onSaveInstanceState 使用的區(qū)別在于 onSaveInstanceState 只能在其參數(shù)中的 Bundle 對(duì)象中寫入數(shù)據(jù),而 onRetainCustomNonConfigurationInstance 返回的類型是 Any(Java Object)不限制數(shù)據(jù)類型。老樣子看一下這組方法的源碼調(diào)用流程。

onRetainCustomNonConfigurationInstance

onRetainCustomNonConfigurationInstance 是在 ComponentActivity 中定義的,默認(rèn)實(shí)現(xiàn)返回 null,其在 onRetainNonConfigurationInstance 方法中被調(diào)用:

ComponentActivity.java

public Object onRetainCustomNonConfigurationInstance() {
    // ComponentActivity 中默認(rèn)返回 null
    return null;
}

public final Object onRetainNonConfigurationInstance() {
    // 保存在了 custom 變量中
    Object custom = onRetainCustomNonConfigurationInstance();
    // 這里已經(jīng)出現(xiàn) ViewModel 相關(guān)的源碼了,這里先按下不表
    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            viewModelStore = nc.viewModelStore;
        }
    }

    if (viewModelStore == null && custom == null) {
        return null;
    }
    // 新建 NonConfigurationInstances 對(duì)象
    NonConfigurationInstances nci = new NonConfigurationInstances();
    // custom 賦值給了 NonConfigurationInstances 對(duì)象
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}

從 ComponentActivity 的這部分源碼中可以看出保存的數(shù)據(jù)最終放在了 NonConfigurationInstances 對(duì)象的 custom 屬性中;接著找 onRetainNonConfigurationInstance 的定義,在 Activity 中:

Activity.java

public Object onRetainNonConfigurationInstance() {
    // 默認(rèn)返回 null
    return null;
}

NonConfigurationInstances retainNonConfigurationInstances() {
    // ComponentActivity 中返回的 NonConfigurationInstances 對(duì)象
    Object activity = onRetainNonConfigurationInstance();
    // ...
    // 注意 這里有新建另一個(gè) NonConfigurationInstances 對(duì)象
    NonConfigurationInstances nci = new NonConfigurationInstances();
    // ComponentActivity 中返回的 NonConfigurationInstances 對(duì)象
    // 存儲(chǔ)到了新的 NonConfigurationInstances 中的 activity 屬性中
    nci.activity = activity;
    // ...
    return nci;
}

在 Activity 類中相當(dāng)于做了一層套娃,又新建了一個(gè) NonConfigurationInstances 對(duì)象,將 ComponentActivity 中返回的 NonConfigurationInstances 對(duì)象存了進(jìn)去;

其實(shí)源碼看到這里就可以了,不過(guò)本著刨根問(wèn)底的原則,我們接著再看一下 NonConfigurationInstances 到底存在了哪里?在 ActivityThread.java 中找到了調(diào)用 retainNonConfigurationInstances 的地方:

ActivityThread.java

void performDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) {
    // ...
    // 這個(gè) r 是參數(shù)中的 ActivityClientRecord
    r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
}

和 onSaveInstanceState 一樣存儲(chǔ)在了 ActivityClientRecord 中,只不過(guò)換了一個(gè)屬性罷了。

getLastCustomNonConfigurationInstance

看完了存儲(chǔ)的流程,簡(jiǎn)單來(lái)看看取數(shù)據(jù)的流程。既然存的時(shí)候套娃了一下 NonConfigurationInstances,那取數(shù)據(jù)的時(shí)候肯定也需要套娃:

ComponentActivity.java

public Object getLastCustomNonConfigurationInstance() {
    // 通過(guò) getLastNonConfigurationInstance 獲取 NonConfigurationInstances
    NonConfigurationInstances nc = (NonConfigurationInstances)
            getLastNonConfigurationInstance();
    // 返回 custom
    return nc != null ? nc.custom : null;
}

那么在 Activity 中肯定還需要取一次 ActivityClientRecord 中的 NonConfigurationInstances:

Activity.java

NonConfigurationInstances mLastNonConfigurationInstances;

public Object getLastNonConfigurationInstance() {
    // 返回其 activity 字段
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}

// mLastNonConfigurationInstances 賦值在 attach 方法中
final void attach(Context context, /*參數(shù)太多 省略了*/ NonConfigurationInstances lastNonConfigurationInstances) {
    // ...
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    // ...
}

可以看出在 Activity attach 方法中就已經(jīng)拿到了套娃后的 NonConfigurationInstances 對(duì)象,我們都知道 Activity attach 方法是在 ActivityThread 的 performLaunchActivity 中調(diào)用,看一下源碼:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // ...
    // 參數(shù)太多 省略了
    // 可以看到是從 ActivityClientRecord 中取出傳入的
    activity.attach(appContext, r.lastNonConfigurationInstancesn);
    // ...
}

小節(jié)總結(jié)

兩種方式都是將數(shù)據(jù)保存到了 ActivityClientRecord 中,不同的是前者限制了 Bundle 類型,后者不限制類型(ViewModel 采用的就是后者這組方法實(shí)現(xiàn)),不過(guò)后者已經(jīng)在源碼中被標(biāo)記了刪除,并不影響使用,標(biāo)記刪除是為了讓開發(fā)者們利用 ViewModel 來(lái)接管這種需求。下面我們就正式進(jìn)入 ViewModel 源碼。

源碼分析

前置知識(shí)有點(diǎn)長(zhǎng),不過(guò)也幾乎把 ViewModel 的原理說(shuō)透了,ViewModel 的保存、恢復(fù)是利用了系統(tǒng)提供的方法,不過(guò)還有些細(xì)節(jié)還需要在源碼中探索,比如:如何實(shí)現(xiàn) Activity/Fragment 共享 ViewModel?接下來(lái)就來(lái)深入 ViewModel 源碼。

創(chuàng)建

先來(lái)以 Activity 中創(chuàng)建 ViewModel 的這段代碼入手:

val vm by viewModels<MainViewModel>()

查看 viewModels 源碼:

// 這是一個(gè) ComponentActivity 的擴(kuò)展方法
@MainThread // 在主線程中使用
inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
    // 從命名也可以看出是一個(gè)工廠模式,默認(rèn)是 null
    noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
    // 默認(rèn) factoryProducer 為 null
    // 返回的是 AndroidViewModelFactory
    val factoryPromise = factoryProducer ?: {
        val application = application ?: throw IllegalArgumentException(
            "ViewModel can be accessed only when Activity is attached"
        )
        AndroidViewModelFactory.getInstance(application)
    }
    
    // 返回了一個(gè) ViewModelLazy 對(duì)象,將 viewModelStore、factoryProducer 傳入
    return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
}

到這里先暫??匆幌?AndroidViewModelFactory 是如何初始化的,以及 viewModelStore 是什么東東:

ViewModelProvider.kt

private var sInstance: AndroidViewModelFactory? = null

@JvmStatic
public fun getInstance(application: Application): AndroidViewModelFactory {
    if (sInstance == null) {
        sInstance = AndroidViewModelFactory(application)
    }
    return sInstance!!
}

是一個(gè)單例模式,直接對(duì) AndroidViewModelFactory 進(jìn)行實(shí)例化,再來(lái)看看 mViewModelStore

ComponentActivity.java

// 都是定義在 ComponentActivity 中的變量,默認(rèn) null
private ViewModelStore mViewModelStore;

public ViewModelStore getViewModelStore() {
    // ...
    if (mViewModelStore == null) { // 第一次啟動(dòng) activity 為 null
        // 獲取保存的數(shù)據(jù)
        NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
         // 優(yōu)先從保存的數(shù)據(jù)中獲取
        if (nc != null) {
            mViewModelStore = nc.viewModelStore;
        }
        // 默認(rèn)返回 ViewModelStore
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}

ViewModelStore 內(nèi)部?jī)H僅是管理一個(gè) Map<String, ViewModel>,用于緩存、清理創(chuàng)建的 ViewModel。

回過(guò)頭接著看擴(kuò)展方法 viewModels 返回的 ViewModelLazy:

public class ViewModelLazy<VM : ViewModel> @JvmOverloads constructor(
    private val viewModelClass: KClass<VM>, // ViewModel 的 class
    private val storeProducer: () -> ViewModelStore, // 默認(rèn)是 ViewModelStore
    private val factoryProducer: () -> ViewModelProvider.Factory, // 這里就是 mDefaultFactory
    private val extrasProducer: () -> CreationExtras = { CreationExtras.Empty } // 
) : Lazy<VM> { // 注意這里返回的 Lazy,延遲初始化
    private var cached: VM? = null

    override val value: VM
        get() { // 由于返回的是 Lazy,也就是當(dāng)使用 ViewModel 時(shí)才會(huì)調(diào)用 get
            val viewModel = cached
            return if (viewModel == null) { // 第一次調(diào)用是 null,進(jìn)入 if
                val factory = factoryProducer() // mDefaultFactory
                val store = storeProducer() // ViewModelStore
                ViewModelProvider( // 生成 ViewModelProvider 對(duì)象
                    store,
                    factory,
                    extrasProducer()
                ).get(viewModelClass.java).also { // 調(diào)用其 get 方法獲取 ViewModel
                    cached = it  // 保存到 cached 變量
                } 
            } else {
                viewModel
            }
        }
    
    override fun isInitialized(): Boolean = cached != null
}

這里又出現(xiàn)了一個(gè)陌生的對(duì)象 CreationExtras,其內(nèi)部也是一個(gè) map,可以理解為一個(gè)鍵值對(duì)存儲(chǔ)對(duì)象,只不過(guò)他的 Key 是一個(gè)特殊類型。

接著查看 ViewModelProvider 的 get 方法是如何創(chuàng)建 ViewModel 的:

// 存儲(chǔ)ViewModel的key的前綴
internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"

public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
    val canonicalName = modelClass.canonicalName
        ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
    // 調(diào)用重載方法,拼接 key 傳入
    // 當(dāng)前key即為:androidx.lifecycle.ViewModelProvider.DefaultKey$com.xxx.MainViewModel
    return get("$DEFAULT_KEY:$canonicalName", modelClass)
}

@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
    val viewModel = store[key] // 優(yōu)先從 ViewModelStroe 中獲取緩存
    if (modelClass.isInstance(viewModel)) { // 如果類型相同 直接返回
        // 這里我們的 factory 是 AndroidViewModelFactory 所以不會(huì)走這行代碼
        (factory as? OnRequeryFactory)?.onRequery(viewModel)
        return viewModel as T
    }
    // ...
    // 這里的 defaultCreationExtras 是上一步驟中的 CreationExtras,默認(rèn)值為 CreationExtras.Empty
    // MutableCreationExtras 包裝一層就是將 defaultCreationExtras 中所有的鍵值對(duì)都copy一份
    val extras = MutableCreationExtras(defaultCreationExtras)
    // 將當(dāng)前 ViewModel 的 key 存儲(chǔ)進(jìn)去
    extras[VIEW_MODEL_KEY] = key
    
    return try {
        // 優(yōu)先調(diào)用雙參數(shù)方法
        factory.create(modelClass, extras)
    } catch (e: AbstractMethodError) {
        // 調(diào)用雙參數(shù)方法發(fā)生異常再調(diào)用單參數(shù)方法
        factory.create(modelClass)
    }.also { 
        // 獲取到 ViewModel 后存儲(chǔ)到 viewModelStore 中
        // 再提一嘴 viewModelStore 是在 ComponentActivity 中定義 
        store.put(key, it) 
    }
}

終于到了創(chuàng)建 ViewModel 的部分了,直接去看 AndroidViewModelFactory 的 create 方法:

ViewModelProvider.kt

override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
    // application 不為 null 調(diào)用單參數(shù)方法
    // 在新建 AndroidViewModelFactory 已經(jīng)傳入了 application,一般情況不為 null
    return if (application != null) { 
        create(modelClass)
    } else { 
        // application 如果為 null,則會(huì)從傳入的 extras 中嘗試獲取
        val application = extras[APPLICATION_KEY]
        if (application != null) {
            // 這個(gè) create 也是雙參數(shù),但不是遞歸,第二個(gè)參數(shù)是 application,源碼貼在下面
            create(modelClass, application)
        } else {
            // 如果 application 仍然為 null,且 ViewModel 類型為 AndroidViewModel 則拋異常
            if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
                throw IllegalArgumentException(...)
            }
            // 類型不是 AndroidViewModel 則根據(jù) class 創(chuàng)建
            // 注意這里調(diào)用的 super.create 是父類方法
            // 父類方法直接根據(jù) modelClass.newInstance() 創(chuàng)建,就一行就不貼源碼了
            super.create(modelClass)
        }
    }
}

override fun <T : ViewModel> create(modelClass: Class<T>): T {
    return if (application == null) { // application 為 null 直接拋異常
        throw UnsupportedOperationException(...)
    } else {
        // 調(diào)用下面的雙參數(shù)方法
        create(modelClass, application)
    }
}

private fun <T : ViewModel> create(modelClass: Class<T>, app: Application): T {
    // 如果是 AndroidViewModel 類型則獲取帶 application 的構(gòu)造參數(shù)創(chuàng)建
    return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
        modelClass.getConstructor(Application::class.java).newInstance(app)
    } else {
        // 直接調(diào)用父類 create 方法通過(guò) modelClass.newInstance() 創(chuàng)建
        super.create(modelClass)
    }
}

至此 Activity 中的 ViewModel 創(chuàng)建過(guò)程源碼就全部分析完了,總結(jié)一下:Activity 中的 ViewModel 創(chuàng)建都是通過(guò)單例工廠 AndroidViewModelFactory 的 create 方法中反射創(chuàng)建,在調(diào)用 create 創(chuàng)建前會(huì)生成字符串 key,創(chuàng)建完成后會(huì)將 key 和 vm 對(duì)象存儲(chǔ)到 ViewModelStore 中,后續(xù)獲取將優(yōu)先從 ViewModelStore 緩存中獲取。

ViewModelStore 是定義在 ComponentActivity 中的,ViewModel 生命周期 “長(zhǎng)于” Activity 的原理跟這個(gè) ViewModelStore 脫不了干系。

恢復(fù)

前面小節(jié)提過(guò),ViewModel 的恢復(fù)利用的是 onRetainNonConfigurationInstance 方法,ViewModelStore 又是定義在 ComponentActivity 中,那么直接去看 ComponentActivity 這部分的源碼:

ComponentActivity.java

public final Object onRetainNonConfigurationInstance() {
    // 留給開發(fā)者使用的字段
    Object custom = onRetainCustomNonConfigurationInstance();
    
    // 獲取當(dāng)前 Activity 的 mViewModelStore
    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) { 
        // 如果為 null 則嘗試獲取上一次保存的數(shù)據(jù)
        NonConfigurationInstances nc =  (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // 獲取上一次存儲(chǔ)的 viewModelStore
            viewModelStore = nc.viewModelStore;
        }
    }
    // ...
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom; // 開發(fā)者用的字段
    nci.viewModelStore = viewModelStore; // 保存 viewModelStore 的字段
    return nci;
}

再來(lái)看一看 ViewModelStore 的獲取方法:

public ViewModelStore getViewModelStore() {
    // ...
    if (mViewModelStore == null) {
        NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
         // 優(yōu)先從保存的數(shù)據(jù)中獲取 viewModelStore
        if (nc != null) {
            mViewModelStore = nc.viewModelStore;
        }
        // 獲取不到才會(huì)新建
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}

Activity 獲取 mViewModelStore 時(shí)優(yōu)先從 getLastNonConfigurationInstance 獲取到 NonConfigurationInstances 對(duì)象,再?gòu)钠渲蝎@取 viewModelStore,這樣在當(dāng)前 Activity 作用域中創(chuàng)建過(guò)的 ViewModel 都存儲(chǔ)在 ViewModelStore 中,當(dāng)需要再次使用時(shí)走 ViewModel 創(chuàng)建流程會(huì)直接從 ViewModelStore 中返回。

最后

再了解了 onRetainNonConfigurationInstance 這組方法之后再來(lái)探究 ViewModel 的恢復(fù)原理就很簡(jiǎn)單了,onRetainNonConfigurationInstance 也被標(biāo)記為了刪除,google 也希望開發(fā)者盡可能的使用 ViewModel 來(lái)保存數(shù)據(jù)(臨時(shí)數(shù)據(jù))。

onRetainNonConfigurationInstance 雖然被標(biāo)記為刪除,但仍然可以正常使用,相比于 onSaveInstanceState 沒(méi)有了數(shù)據(jù)類型限制,但并不意味著我們可以隨意存儲(chǔ),比較大的數(shù)據(jù)還是應(yīng)該考慮持久化存儲(chǔ)。

以上就是源碼解析Android Jetpack組件之ViewModel的使用的詳細(xì)內(nèi)容,更多關(guān)于Android Jetpack ViewModel的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android startActivityForResult的基本用法詳解

    Android startActivityForResult的基本用法詳解

    這篇文章主要介紹了Android startActivityForResult的基本用法詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • 圖解Eclipse在線安裝ADT插件過(guò)程

    圖解Eclipse在線安裝ADT插件過(guò)程

    這篇文章主要以圖解的方式為大家分享了Eclipse在線安裝ADT插件過(guò)程,需要的朋友可以參考下
    2015-12-12
  • Android HelloChart開源庫(kù)圖表之折線圖的實(shí)例代碼

    Android HelloChart開源庫(kù)圖表之折線圖的實(shí)例代碼

    這篇文章主要介紹了Android HelloChart開源庫(kù)圖表之折線圖的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • Android Bluetooth藍(lán)牙技術(shù)初體驗(yàn)

    Android Bluetooth藍(lán)牙技術(shù)初體驗(yàn)

    這篇文章主要介紹了Android Bluetooth藍(lán)牙技術(shù)初體驗(yàn)的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • Android使用surfaceView自定義抽獎(jiǎng)大轉(zhuǎn)盤

    Android使用surfaceView自定義抽獎(jiǎng)大轉(zhuǎn)盤

    這篇文章主要為大家詳細(xì)介紹了Android使用surfaceView自定義抽獎(jiǎng)大轉(zhuǎn)盤,熟練掌握SurfaceVie實(shí)現(xiàn)抽獎(jiǎng)大轉(zhuǎn)盤,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Android系統(tǒng)檢測(cè)程序內(nèi)存占用各種方法

    Android系統(tǒng)檢測(cè)程序內(nèi)存占用各種方法

    這篇文章主要介紹了Android系統(tǒng)檢測(cè)程序內(nèi)存占用各種方法,本文講解了檢查系統(tǒng)總內(nèi)存、檢查某個(gè)程序的各類型內(nèi)存占用、檢查程序狀態(tài)、檢查程序各部分的內(nèi)存占用等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • Android畫中畫窗口開啟方法

    Android畫中畫窗口開啟方法

    Android8.0 Oreo(API Level26)允許活動(dòng)啟動(dòng)畫中畫Picture-in-picture(PIP)模式。PIP是一種特殊類型的多窗口模式,主要用于視頻播放。PIP模式已經(jīng)可用于Android TV,而Android8.0則讓該功能可進(jìn)一步用于其他Android設(shè)備
    2023-01-01
  • Android自定義水平進(jìn)度條的圓角進(jìn)度

    Android自定義水平進(jìn)度條的圓角進(jìn)度

    這篇文章主要為大家詳細(xì)介紹了Android自定義水平進(jìn)度條的圓角進(jìn)度,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 詳解RecyclerView設(shè)置背景圖片長(zhǎng)寬一樣(以GridLayoutManager為例)

    詳解RecyclerView設(shè)置背景圖片長(zhǎng)寬一樣(以GridLayoutManager為例)

    這篇文章主要介紹了詳解RecyclerView設(shè)置背景圖片長(zhǎng)寬一樣(以GridLayoutManager為例),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • Android使用ViewPager實(shí)現(xiàn)啟動(dòng)引導(dǎo)頁(yè)

    Android使用ViewPager實(shí)現(xiàn)啟動(dòng)引導(dǎo)頁(yè)

    這篇文章主要為大家詳細(xì)介紹了Android使用ViewPager實(shí)現(xiàn)第一次啟動(dòng)引導(dǎo)頁(yè),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-07-07

最新評(píng)論