ViewModel 在 Activity 中的实现原理

系统源码参考自 Android API 30 Platform,以及 androidx.lifecycle:lifecycle-viewmodel:2.2.0


在文章开始之前,有如下几点疑惑,先记录下来:

  1. ViewModel#onCleared() 的调用时机 ?
  2. ViewModel 与 onSaveInstanceState() 有联系吗?或者有什么区别吗?
  3. ViewModel 是否涉及序列化与反序列化?
  4. 一个 Activity 中是否支持多个 ViewModel ?
  5. ViewModelProvider#get() 的使用时机。

1. 与 ViewModel 相关的类

1.1 ViewModelStoreViewModelStoreOwner

ViewModel 实现的关键就是 ViewModelStore,其内部有一个 HashMap<String, ViewModel> 用于存储多个 ViewModel 实例,即本质上就是一个用来维护多个 ViewModel 实例的 map 容器。

public class ViewModelStore {
   
   

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
   
   
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
   
   
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
   
   
        return mMap.get(key);
    }

    ...
}

另外,还涉及到 ViewModelStoreOwner 接口。

public interface ViewModelStoreOwner {
   
   
    @NonNull
    ViewModelStore getViewModelStore();
}

1.2 androidx.activity.ComponentActivity

androidx.activity.ComponentActivity(源码基于 androidx.activity:activity:1.1.0),就是我们常用的 androidx.appcompat.app.AppCompatActivity的父类。

androidx.activity.ComponentActivity 继承自 androidx.core.app.ComponentActivity,且实现了 ViewModelStoreOwner 接口,同时内部维护了对应的成员变量 mViewModelStoreViewModelStore 类型的)。
在这里插入图片描述

// androidx.activity.ComponentActivity

@NonNull
@Override
public ViewModelStore getViewModelStore() {
   
   
	if (getApplication() == null) {
   
   
    	throw new IllegalStateException("Your activity is not yet attached to the "
            + "Application instance. You can't request ViewModel before onCreate call.");
	}
    if (mViewModelStore == null) {
   
   
      	// NonConfigurationInstances 为 ComponentActivity 中的内部静态类
        NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
   
   
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        // 如果前面都没有获取到 ViewModelStore 实例,则这里直接实例化一个新的
        if (mViewModelStore == null) {
   
   
            mViewModelStore = new ViewModelStore();
        }
    }
    return mViewModelStore;
}

static final class NonConfigurationInstances {
   
   
    Object custom;
    ViewModelStore viewModelStore;
}

getLastNonConfigurationInstance()android.app.Activity 的成员方法。

// android.app.Activity

/**
 * Retrieve the non-configuration instance data that was previously
 * returned by {@link #onRetainNonConfigurationInstance()}.  This will
 * be available from the initial {@link #onCreate} and
 * {@link #onStart} calls to the new instance, allowing you to extract
 * any useful dynamic state from the previous instance.
 *
 * <p>Note that the data you retrieve here should <em>only</em> be used
 * as an optimization for handling configuration changes.  You should always
 * be able to handle getting a null pointer back, and an activity must
 * still be able to restore itself to its previous state (through the
 * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
 * function returns null.
 *
 * <p><strong>Note:</strong> For most cases you should use the {@link Fragment} API
 * {@link Fragment#setRetainInstance(boolean)} instead; this is also
 * available on older platforms through the Android support libraries.
 *
 * @return the object previously returned by {@link #onRetainNonConfigurationInstance()}
 */
@Nullable
public Object getLastNonConfigurationInstance() {
   
   
  	// mLastNonConfigurationInstances 则是在 Activity 中定义的内部静态类 ComponentActivity.NonConfigurationInstances 类型
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}

static final class NonConfigurationInstances {
   
   
    Object activity;
    HashMap<String, Object> children;
    FragmentManagerNonConfig fragments;
    ArrayMap<String, LoaderManager> loaders;
    VoiceInteractor voiceInteractor;
}

android.app.Activity 内部维护着成员变量 mLas

`ViewModel` 与 `onRetainNonConfigurationInstance()` 是 Android 中用于在配置变更期间保留数据的两种机制,它们在实现原理和使用方式上各有特点,适用于不同的开发场景。 ### 一、实现机制的相同点 1. **配置变更期间保留数据**:两者都能在配置变更(如屏幕旋转、语言切换)时保留数据,避免 Activity 被销毁后数据丢失。 2. **不依赖 Activity 的生命周期**:它们都可以在 Activity 重建后继续存在,直到其关联的作用域真正被销毁。 3. **避免重复初始化**:都可用于保存耗时初始化的数据,如网络请求、播放器实例等,从而提高应用性能。 ### 二、实现机制的不同点 | 对比维度 | `ViewModel` | `onRetainNonConfigurationInstance()` | |----------|-------------|----------------------------------------| | **实现原理** | 基于生命周期感知组件,由 `ViewModelProvider` 管理生命周期 | 通过系统回调保存对象实例 | | **数据持有方式** | 通过 `ViewModelStore` 持有 ViewModel 实例 | 返回一个 `Object`,由系统保存并在新 Activity 中恢复 | | **生命周期管理** | 自动管理,与 `Activity` 或 `Fragment` 的生命周期绑定 | 需要手动管理对象的生命周期 | | **内存泄漏风险** | 低,不建议在 ViewModel 中持有 Context | 高,若对象持有旧 Activity 的 Context 会导致内存泄漏 | | **数据恢复方式** | 通过 `ViewModelProvider` 获取 | 通过 `getLastNonConfigurationInstance()` 获取 | | **与架构组件集成** | 支持 `LiveData`、`LiveData`、`DataBinding` 等 Jetpack 组件 | 不支持 Jetpack 架构组件 | | **适用场景** | 推荐用于现代开发,适合大多数数据保存场景 | 适用于旧项目或特定对象的保留,已被 ViewModel 取代 | ### 三、使用方式对比示例 #### 使用 `ViewModel` ```kotlin class MyViewModel : ViewModel() { val data = MutableLiveData<String>() } class MyActivity : AppCompatActivity() { private lateinit var viewModel: MyViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel = ViewModelProvider(this)[MyViewModel::class.java] viewModel.data.observe(this) { // 更新 UI } } } ``` #### 使用 `onRetainNonConfigurationInstance` ```java private MediaPlayer mediaPlayer; @Override public Object onRetainNonConfigurationInstance() { return mediaPlayer; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mediaPlayer = (MediaPlayer) getLastNonConfigurationInstance(); if (mediaPlayer == null) { mediaPlayer = new MediaPlayer(); } } ``` ### 四、总结 `ViewModel` 是 Android Jetpack 提供的一种更现代、更安全的数据保留机制,具有良好的生命周期管理和架构集成能力。而 `onRetainNonConfigurationInstance()` 是一种较早期的机制,在旧项目中仍可见,但容易引发内存泄漏问题。在现代 Android 开发中,推荐优先使用 `ViewModel` 来替代 `onRetainNonConfigurationInstance()`。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值