Jetpack系列-ViewModel的使用及原理浅析

作者:碎星

简介

ViewModel在架构中用于承载业务逻辑和作为容器保存屏幕状态,它可以缓存界面的状态,并且能在配置变更后持久保留相应的界面状态。

在jetpack套件中,ViewModel随lifecycle一起提供。

优势

简介

ViewModel在架构中用于承载业务逻辑和作为容器保存屏幕状态,它可以缓存界面的状态,并且能在配置变更后持久保留相应的界面状态。

在jetpack套件中,ViewModel随lifecycle一起提供。

优势

  • 可以持久的保持界面状态:一是界面因配置变更导致的重建,不会销毁内存中的;二是可以借助SavedStateHandle在进程销毁-重建过程中恢复数据。
  • ViewModel具有作用域(如:Activity、Fragment等),ViewModel中的异步工作将被限定在这个Lifecycle上执行。
  • ViewModel可用用来承载之前处于界面层的部分业务逻辑:将数据层传递的数据处理成界面状态。
  • 可以作为桥梁在Activity与Fragment、Fragment与Fragment之间共享数据。

使用

定义

// 直接继承ViewModel
class DemoViewModel : ViewModel() {
    private val api = MyService()

    // 通常配合LiveData、StateFlow这些可感知对象为界面提供状态。
    private val _uiState = MutableLiveData("")
    val uiState: LiveData<String> = _uiState
    // 使用SharedFlow为界面提供事件回调
    private val _uiEvent = MutableSharedFlow<DemoEvent>()
    val uiEvent = _uiEvent.asSharedFlow()

    fun reqData(param: String) {
        // ViewModel能自动处理协程scope的生命周期
        viewModelScope.launch(Dispatchers.IO) {
            _uiEvent.emit(DemoEvent.Loading)
           try {
                val data = api.reqData(param)
                _uiState.postValue("rsp: $data")
            } finally {
               _uiEvent.emit(DemoEvent.Completed)
            }
        }
    }
}

基本用法

在androidx的Activity中使用:

class ViewModelDemoActivity : AppCompatActivity() {
    private lateinit var viewModel: DemoViewModel
    // viewmodel的ktx扩展库中提供了委托方式获取viewmodel实例
//  private val viewModel: DemoViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_view_model_demo)
        
        // ViewModelProvider是获取viewmodel的基础工具,它需要一个ViewModelStoreOwner实例
        // 这个实例就是用来存储和管理viewmodel的,androidx的ComponentActivity
        // 实现了这个接口,因此可以直接使用AppCompatActivity来初始化ViewModelProvider。
        viewModel = ViewModelProvider(this).get(DemoViewModel::class.java)

        // 监听界面状态以及事件,并做出响应
        viewModel.uiState.observe(this) {
            Log.d(TAG, "received response: $it")
        }
        viewModel.uiEvent
            .onEach { showLoading(it == DemoEvent.Loading) }
            .launchIn(lifecycleScope)
        viewModel.reqData(param)
    }
}

在androidx的Fragment中使用:

class DemoFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // jetpack fragment也实现了ViewModelStoreOwner接口,因此也可以用于获取和管理viewmodel
        val selfViewModel = ViewModelProvider(this).get(FragmentViewModel::class.java)
    }
    
    override fun onAttach(context: Context) {
        super.onAttach(context)
        // 可以获取到Activity或者其它Fragment的ViewModel,只需要在构造ViewModelProvider
        // 时传递了对应的ViewModelStoreOwner。这个实例和DemoActivity
        // 中获取到的是同一个实例,因此你可以通过这个实例实现和Activity的通信。
        val parentViewModel = ViewModelProvider(requireActivity())
            .get(DemoViewModel::class.java)
    }
}

SavedStateHandle

SavedStateHandle主要用于在进程销毁-重建过程中恢复数据,它可以将数据持久化到存储中,并在重建后恢复数据。

class DemoViewModel(val savedState: SavedStateHandle) : ViewModel() {
    // 可以使用getLiveData将要获取的数据转为LiveData
    private val _savedData = savedState.getLiveData<String>(DATA_KEY)
    val savedData: LiveData<String> = _savedData  

    fun saveData(data: String) {
        savedState[DATA_KEY] = data
    }

    fun readData(): String? {
        // 也可以直接获取
        return savedState[DATA_KEY]
    }

    companion object {
        private const val DATA_KEY = "data"
    }
}

AndroidViewModel

有时候ViewModel中可能会需要使用到Android Context(获取文本、颜色等资源),此时可以使用AndroidViewModel,它提供了一个getApplication()方法,可以很方便的获取上下文实例。使用方式如下:

class DemoViewModel(application: Application) 
    : AndroidViewModel(application) { 
    fun getString() = application.getString(R.string.hint_txt)
}

带参数的ViewModel

前面几个小节我们都假定了使用androidx的组件作为ViewModelStoreOwner来构造ViewModelProvider。这些androidx的组件会帮助我们自动提供ViewModel所依赖的SavedStateHandleApplication

然而,当我们使用自定义ViewModelStoreOwner时,或者想向ViewModel传递其它类型的参数时,就需要自定义ViewModeProvider.Factory了。

假如我们有如下ViewModel,它需要接收一个Repository作为参数:

class MyViewModel(
    private val myRepository: MyRepository
) : ViewModel() { }

为了实例化MyViewModel,我们需要再定义一个Factory,然后在create方法中获取依赖对象,构造ViewModel实例:

val factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(
        modelClass: Class<T>,
        extras: CreationExtras
    ): T {
        val repo = MyRepository(extras[MY_URL])
        return MyViewModel(repo) as T
    }
}

上面的CreationExtras用于从外界向ViewModel构造过程传递参数,它在ViewModelProvider构造时与factory实例一起传递给ViewModelProvider:

val extras = MutableCreationExtras().apply {
    this[MY_URL] = "https://..."
}
val viewModel = ViewModelProvider(this, factory, extras)
    .get(MyViewModel::class.java)

原理分析

ViewModel的获取过程

ViewModelProvider的构造

顾名思义,ViewModelProvider就是用于提供ViewModel实例的类,它在构造时需要接受三个参数:

public open class ViewModelProvider
constructor(
    private val store: ViewModelStore,
    private val factory: Factory,
    private val defaultCreationExtras: CreationExtras = CreationExtras.Empty,
)
  • ViewModelStore:用于存储ViewModel实例的类,内部持有一个HashMap保存实例,ViewModelProvider会将创建好的ViewModel实例保存到ViewModelStore中,之后再需要此类ViewModel的实例时就直接从中读取。
  • ViewModelProvider.Factory:前文已经提到,这是用于创建ViewModel实例的工厂,ViewModelProvider当需要ViewModel的实例又在ViewModelStore中没有找到对应实例时就会调用工厂的create方法创建。
  • CreationExtras:前文也已提到,它用于在创建ViewModel实例时从外界向构造过程传递参数,内部持有一个MutableMap,以key-value的形式存储和查找参数。

虽然ViewModelProvider需要三个参数来构造,但在实际使用中我们往往只在构造时传递了一个ViewModelStoreOwnerViewModelStoreOwner很好理解,可以用来提供ViewModelStore,而剩下两个参数,框架则提供了一系列的默认规则。

public constructor(
    owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))

ViewModelStore的获取

通常情况下ViewModelStoreViewModelStoreOwner提供,ViewModelStoreOwner是一个接口,里面只声明了一个getViewModelStore函数。androidx里的ComponentActivityFragmentFragmentViewLifecycleOwner等都实现了这个接口,下面我们看一看ComponentActivity中是如何实现的:

public ViewModelStore getViewModelStore() {
    ensureViewModelStore();
    return mViewModelStore;
}

void ensureViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
        // 这里会尝获取配置变更前保存的实例,这是ViewModel在配置变更后仍能保持数据的关键
        if (nc != null) {
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
}

默认工厂和及构造参数

defaultFactory, defaultCreationExtras用于提供默认的ViewModelProvider.FactoryCreationExtras

internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
    if (owner is HasDefaultViewModelProviderFactory)
        owner.defaultViewModelProviderFactory 
    else instance

internal fun defaultCreationExtras(owner: ViewModelStoreOwner): CreationExtras =
    if (owner is HasDefaultViewModelProviderFactory) {
        owner.defaultViewModelCreationExtras
    else CreationExtras.Empty

可以看到,两个方法首先都尝试将ViewModelStoreOwner实例转为HasDefaultViewModelProviderFactory,然后从中获取对应的默认值。如果没获取到,则返回ViewModelProvider自己提供的默认值。

先来看下ViewModelProvider提供的默认值:

public open class NewInstanceFactory : Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return try {
            modelClass.newInstance()
        } catch (...) {
            ...
        }
    }
    public companion object {
        private var sInstance: NewInstanceFactory? = null
        public val instance: NewInstanceFactory get() {
            if (sInstance == null) sInstance = NewInstanceFactory()
            return sInstance!!
        }
    }
}

可以看到,这个工厂通过直接调用Class的newInstance方法直接创建实例,这种情况下ViewModel必需要提供无参构造函数。

接下来我们看HasDefaultViewModelProviderFactory,这也是一个接口,里面声明了getDefaultViewModelProviderFactorygetDefaultViewModelCreationExtras两个方法,分别用于获取默认的工厂实例与默认的构造参数。androidx中的ComponentActivityFragment也实现了这个接口,以ComponentActivity中的实现为例:

public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
    if (mDefaultFactory == null) {
        mDefaultFactory = new SavedStateViewModelFactory(
            getApplication(),
            this,
            getIntent() != null ? getIntent().getExtras() : null);
    }
    return mDefaultFactory;
}

public CreationExtras getDefaultViewModelCreationExtras() {
    MutableCreationExtras extras = new MutableCreationExtras();
    if (getApplication() != null) {
        extras.set(ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY, getApplication());
    }
    extras.set(SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY, this);
    extras.set(SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY, this);
    if (getIntent() != null && getIntent().getExtras() != null) {
        extras.set(SavedStateHandleSupport.DEFAULT_ARGS_KEY, getIntent().getExtras());
    }
    return extras;
}

ComponentActivity会提供一个SavedStateViewModelFactory实例,并且会提供一个预置了一些内容的CreationExtras实例,里面有Application实例、SavedStateRegistryOwner 的实例、ViewModelStoreOwner的实例,以及Intent中extras参数bundle。

然后是SavedStateViewModelFactory,我们直接看create方法:

override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
    val key = extras[ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY]
        ?: throw IllegalStateException("VIEW_MODEL_KEY must always be provided by ViewModelProvider")

    return if (extras[SAVED_STATE_REGISTRY_OWNER_KEY] != null &&
        extras[VIEW_MODEL_STORE_OWNER_KEY] != null) {
        val application = extras[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]
        val isAndroidViewModel = AndroidViewModel::class.java.isAssignableFrom(modelClass)
        val constructor: Constructor<T>? = if (isAndroidViewModel && application != null) {
            findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE)
        } else {
            findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE)
        }
        // doesn't need SavedStateHandle
        if (constructor == null) {
            return factory.create(modelClass, extras)
        }
        val viewModel = if (isAndroidViewModel && application != null) {
            newInstance(modelClass, constructor, application, extras.createSavedStateHandle())
        } else {
            newInstance(modelClass, constructor, extras.createSavedStateHandle())
        }
        viewModel
    } else {
        // 这里是为了兼容旧版本
        ...
    }
}

除开旧版本的兼容逻辑,上面的代码根据是否使用SavedStateHandle分为两类:当不使用SavedStateHandle时,将ViewModel的构造请求发送给内部的AndroidViewModelFactory实例来处理;当使用SavedStateHandle时,则自己调用createSavedStateHandle方法创建SavedStateHandle实例,然后创建对应的ViewModel实例。关于SavedStateHandle的分析见后文。

获取ViewModel

回到开始,我们通过调用ViewModelProvider实例的get方法来获取ViewModel实例:

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")
    return get("${ViewModelProvider.AndroidViewModelFactory.DEFAULT_KEY}:$canonicalName", modelClass)
}

public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
    val viewModel = store[key]
    if (modelClass.isInstance(viewModel)) {
        (factory as? ViewModelProvider.OnRequeryFactory)?.onRequery(viewModel)
        return viewModel as T
    } else {
        if (viewModel != null) { }
    }
    val extras = MutableCreationExtras(defaultCreationExtras)
    extras[ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY] = key
    return try {
        factory.create(modelClass, extras)
    } catch (e: AbstractMethodError) {
        factory.create(modelClass)
    }.also { store.put(key, it) }
}

获取实例需要两个参数:key和要获取的ViewModel所属类的Class对象,ViewModelProvider会从ViewModelStore中根据key查找是否有现成的实例,有就直接使用,没有就调用Factory的create创建一个。

生命周期管理的实现

ViewModel的作用域会被限定为实例化时使用的ViewModelStoreOwnerViewModelStoreOwner结束生命周期时,ViewModel就会自动回调onCleared方法用于清理依赖生命周期的工作或者对象。

class MyViewModel(
    private val coroutineScope: CoroutineScope =
        CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
) : ViewModel() {
    override fun onCleared() {
        coroutineScope.cancel()
    }
}

在2.5及更高版本的lifecycle库中,ViewModel提供了更多的支持:

  • ViewModel可以接受多个Closeable对象,ViewModel会在清除时自动调用这些对象的close方法。
  • ViewModel提供了addCloseablesetTagIfAbsent等方法,这些方法允许在任意时刻添加Closeable对象到ViewModel中,这些对象同样会被自动清除。

下面还是以ComponentActivity为例看一下清理过程的实现:

public ComponentActivity() {
    Lifecycle lifecycle = getLifecycle ();
    ...
    getLifecycle().addObserver(new LifecycleEventObserver () {
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                // Clear out the available context
                mContextAwareHelper.clearAvailableContext();
                // And clear the ViewModelStore
                if (!isChangingConfigurations()) {
                    getViewModelStore().clear();
                }
            }
        }
    });
}

ComponentActivity会在构造时设置一个lifecycle监听,当activity onDestroy且并非配置改变引起的调用时,执行ViewModelStore的clear方法清空所有的ViewModel,在清空前,会调用每个ViewModel的clear方法。

// ViewModelStore
public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.clear();
    }
    mMap.clear();
}
// ViewModel
final void clear() {
    mCleared = true;
    if (mBagOfTags != null) {
        synchronized (mBagOfTags) {
            for (Object value : mBagOfTags.values()) {
                closeWithRuntimeException(value);
            }
        }
    }
    // We need the same null check here
    if (mCloseables != null) {
        synchronized (mCloseables) {
            for (Closeable closeable : mCloseables) {
                closeWithRuntimeException(closeable);
            }
        }
    }
    onCleared();
}

在ViewModel的clear方法中,对所有保存的Closeable执行close,然后调用onCleared

再看看ktx中的viewModelScope

public val ViewModel.viewModelScope: CoroutineScope
    get() {
        val scope: CoroutineScope? = this.getTag(JOB_KEY)
        if (scope != null) return scope
        return setTagIfAbsent(
            JOB_KEY,
            CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
        )
    }

internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
    override val coroutineContext: CoroutineContext = context

    override fun close() {
        coroutineContext.cancel()
    }
}

其本质也是提供了一个实现Closeable接口的CoroutineScope,然后通过setTagIfAbsent设置给ViewModel。

配置变更后仍保持数据的原理

前面在分析ViewModelStore的获取时,我们知道ComponentActivity在初始化ViewModelStore时,会先调用getLastNonConfigurationInstance,尝试恢复配置未变更前保存的ViewModelStore。与之对应的也有配置变更时保存ViewModelStore的逻辑:

public final Object onRetainNonConfigurationInstance() {
    // Maintain backward compatibility.
    Object custom = onRetainCustomNonConfigurationInstance();
    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        // No one called getViewModelStore(), so see if there was an existing
        // ViewModelStore from our last NonConfigurationInstance
        NonConfigurationInstances nc =
            (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            viewModelStore = nc.viewModelStore;
        }
    }
    if (viewModelStore == null && custom == null) return null;
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}

onRetainNonConfigurationInstance会在Activity配置发生变更(如横竖屏切换)需要重建时,它会将返回的Object直接保存到ActivityClientRecord中:

// ActivityThread
void performDestroyActivity(ActivityClientRecord r, boolean finishing,
     int configChanges, boolean getNonConfigInstance, String reason
) {
    ...
    if (getNonConfigInstance) {
        try {
            r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
        } catch (Exception e) {
           ...
        }
    }
    ...
}

Activity重建时再设置回去:

// ActivityThread
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
     activity.attach(appContext, this, getInstrumentation(), r.token,
         r.ident, app, r.intent, r.activityInfo, title, r.parent,
         r.embeddedID, r.lastNonConfigurationInstances, config,
         r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
         r.assistToken, r.shareableActivityToken);
    ...
}
// Activity
final void attach(Context context, ActivityThread aThread,
     ...
     NonConfigurationInstances lastNonConfigurationInstances,
     ...
) {
    ...
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    ...
}

既然ViewModelStore实例在重建时被保存和恢复了,那么其中的ViewModel及其状态数据也自然不会变化。

SavedStateHandle实现原理

前面我们在分析ComponentActivity中提供的默认工厂SavedStateViewModelFactory时,提到了工厂会在需要使用SavedStateHandle调用createSavedStateHandle创建实例:

public fun CreationExtras.createSavedStateHandle(): SavedStateHandle {
    val savedStateRegistryOwner = this[SAVED_STATE_REGISTRY_OWNER_KEY]
        ?: throw IllegalArgumentException(...)
    val viewModelStateRegistryOwner = this[VIEW_MODEL_STORE_OWNER_KEY]
        ?: throw IllegalArgumentException(...)
    val defaultArgs = this[DEFAULT_ARGS_KEY]
    val key = this[ViewModelProvider.NewInstanceFactory.VIEW_MODEL_KEY] 
        ?: throw IllegalArgumentException(...)
    return createSavedStateHandle(
        savedStateRegistryOwner, viewModelStateRegistryOwner, key, defaultArgs
    )
}

这里会从CreationExtras中获取一些必要参数:

  • savedStateRegistryOwnerSavedStateRegistryOwner是jetpack-savedstate库中的一个接口,实现此接口的类表明可以在应用意外销毁时支持保存/恢复状态。jetpack中的ComponentActivityFragment实现了它。
  • viewModelStateRegistryOwner:这里实际获取的是当前的ViewModelStoreOwner,工厂会将创建出来的SavedStateHandle实例保存在一个专门的ViewModel—SavedStateHandlesVM中以加快访问。
  • defaultArgs:传递给SavedStateHandle的默认参数。
  • key:与待创建ViewModel相关联的键,用于从SavedStateHandlesVM中存取SavedStateHandle实例。
private fun createSavedStateHandle(
    savedStateRegistryOwner: SavedStateRegistryOwner,
    viewModelStoreOwner: ViewModelStoreOwner,
    key: String, defaultArgs: Bundle?
): SavedStateHandle {
    val provider = savedStateRegistryOwner.savedStateHandlesProvider
    val viewModel = viewModelStoreOwner.savedStateHandlesVM
    // If we already have a reference to a previously created SavedStateHandle
    // for a given key stored in our ViewModel, use that. Otherwise, create
    // a new SavedStateHandle, providing it any restored state we might have saved
    return viewModel.handles[key] 
        ?: SavedStateHandle.createHandle(
               provider.consumeRestoredStateForKey(key), defaultArgs
            ).also { viewModel.handles[key] = it }
}

这里获取到的SavedStateProvider专用于保存/恢复SavedStateHandle中状态,这个Provider在ComponentActivity 的构造时通过enableSavedStateHandles创建。

当savedStateHandlesVM没有缓存的实例时,就创建一个新实例返回,这里会先根据key从SavedStateProvider中读取之前保存的状态作为SavedStateHandle构造过程的参数。这样就实现了数据的恢复。

接下来看看数据的保存,我们知道SDK中Activity的状态保存是靠onSaveInstanceState回调实现的,SavedStateHandle也不例外:

// ComponentActivity
protected void onSaveInstanceState(@NonNull Bundle outState) {
    ...
    mSavedStateRegistryController.performSave(outState);
}
// SavedStateRegistryController
fun performSave(outBundle: Bundle) {
    savedStateRegistry.performSave(outBundle)
}
//SavedStateRegistry
fun performSave(outBundle: Bundle) {
    ....
    // 这里获取到所有注册的SavedStateProvider,调用他们的saveState获取到
    // 需要保存的数据,统一的保存到onSaveInstanceState传入的Bundle中
    val it: Iterator<Map.Entry<String, SavedStateProvider>> =
        this.components.iteratorWithAdditions()
    while (it.hasNext()) {
        val (key, value) = it.next()
        components.putBundle(key, value.saveState())
    }
    if (!components.isEmpty) {
        outBundle.putBundle(SAVED_COMPONENTS_KEY, components)
    }
}

用于保存SavedStateHandle中状态的SavedStateHandlesProvider,则早在Activity初始化时注册到了SavedStateRegistry中。来看看它的saveState方法:

private val viewModel by lazy { viewModelStoreOwner.savedStateHandlesVM }

override fun saveState(): Bundle {
    return Bundle().apply {
        ...
        viewModel.handles.forEach { (key, handle) ->
            val savedState = handle.savedStateProvider().saveState()
            if (savedState != Bundle.EMPTY) {
                putBundle(key, savedState)
            }
        }
    }
}

这里的ViewModel就是之前提到的用来保存所有SavedStateHandle实例的SavedStateHandlesVM

SavedStateHandle内部持有一个SavedStateProvider,在保存数据时,会将调用它的onSave方法将SavedStateHandle内部的状态打包成一个Bundle:

private val savedStateProvider = SavedStateRegistry.SavedStateProvider {
    ...
    // Convert the Map of current values into a Bundle
    val keySet: Set<String> = regular.keys
    val keys: ArrayList<String> = ArrayList(keySet.size)
    val value: ArrayList<Any?> = ArrayList(keys.size)
    for (key in keySet) {
        keys.add(key)
        value.add(regular[key])
    }
    bundleOf(SavedStateHandle.KEYS to keys, SavedStateHandle.VALUES to value)
}

总结

ViewModel是Android Jetpack架构组件之一,它可以帮助我们解决Activity/Fragment等组件在配置更改时数据丢失的问题。通过创建ViewModel对象,我们可以将数据存储在其中,从而实现数据的持久化。ViewModel的使用非常灵活,我们可以将其与LiveData、Kotlin协程等其他组件一起使用,以实现更加强大的功能。在本文中,我们介绍了ViewModel的优势、简单的使用方法,并对主要功能的实现原理进行了分析。如果你有任何疑问,欢迎评论我们一起讨论。


为了帮助大家更好的熟知Jetpack 这一套体系的知识点,这里记录比较全比较细致的《Jetpack 入门到精通》(内含Compose) 学习笔记!!! 对Jetpose Compose这块感兴趣的小伙伴可以参考学习下……

Jetpack 全家桶(Compose)

Jetpack 部分

  1. Jetpack之Lifecycle
  2. Jetpack之ViewModel
  3. Jetpack之DataBinding
  4. Jetpack之Navigation
  5. Jetpack之LiveData

Compose 部分
1.Jetpack Compose入门详解
2.Compose学习笔记
3.Compose 动画使用详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值