【源码解读】抽丝剥茧的分析ViewModel的核心原理

本文详细介绍了Android ViewModel类的作用和特点,包括它如何在配置变更后保持数据,避免内存泄漏,以及如何分离视图数据逻辑。通过示例展示了ViewModel的创建和使用,并分析了其源码,揭示了ViewModel在Activity销毁重建后仍然存在的原因。最后,讨论了viewModelScope的关闭时机。

ViewModel背景

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续留存。

摘自 ViewModel概览

详细讲,ViewModel有如下几个特点:

  1. 对于简单数据,Activity被销毁的时候,可以使用onSaveInstanceState()方法从onCreate中恢复其绑定数据,但不适用数量较大的数据,如用户列表或位图。而Viewmodel支持大量数据,也不需要序列化和反序列化操作。
  2. 视图控制器经常需要进程可能需要一些时间才能返回的异步调用。界面控制器需要管理这些调用,并确保系统在其销毁后清理这些调用以避免潜在的内存泄漏。而Viewmodel可以很好的避免内存泄漏。
  3. 如果要求界面控制器也负责从数据库或网络加载数据,那么会使类越发膨胀。为界面控制器分配过多的责任可能会导致单个类尝试自己处理应用的所有工作,而不是将工作委托给其他类。而Viewmodel可以有效的将视图数据逻辑和视图控制器分离开来。

可以看出来VIewmodel是以感知生命周期的形式来存储和管理视图等相关的数据。

基本使用

对Viewmodel的特点有了初步了解后,开始简单操作下。

自定义数据获取类

class TestRepository {
    suspend fun getNameList(): List<String> {
        return withContext(Dispatchers.IO) {
            listOf("哈哈", "呵呵")
        }
    }
}

自定义ViewModel继承ViewMode,实现自定义ViewModel。

class TestViewModel: ViewModel() {
    private val nameList = MutableLiveData<List<String>>()
    val nameListResult: LiveData<List<String>> = nameList
    private val testRepository = TestRepository()
    
    fun getNames() {
        viewModelScope.launch {
            nameList.value = testRepository.getNameList()
        }
    }
}

创建了MutableLiveData,并通过MutableLiveDat的setVale方法来更新数据。

然后就可以在Activity中使用TestViewModel了。

class MainActivity : AppCompatActivity() {
    // 创建 ViewModel 方式 1
    // 通过 kotlin 委托特性创建 ViewModel
    // 需添加依赖 implementation 'androidx.activity:activity-ktx:1.2.3'
    // viewModels() 内部也是通过 创建 ViewModel 方式 2 来创建的 ViewModel
    private val mainViewModel: TestViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate  (savedInstanceState)
        setContentView(R.layout.activity_main)
        // 创建 ViewModel 方式 2
        val mainViewModel = ViewModelProvider(this).get(TestViewModel::class.java)
        mainViewModel.nameListResult.observe(this, {
            Log.i("MainActivity", "mainViewModel: nameListResult: $it")
        })
        mainViewModel.getNames()
    }
}

通过ViemodelProvider配合就可以获得TestViewModel对象,并配合LiveData来观察其变化。通过日志打印我们得到了:

maiinViewModel: nameListResult: [哈哈, 呵呵]

我们再旋转下手机,发现打印出来的信息仍然存在。

maiinViewModel: nameListResult: [哈哈, 呵呵]

说明即使MainActivity被重建了,而ViewModel的实例对象依然存在,内部的LiveData也没有变,是不是很神奇!!!

Activity旋转屏幕后ViewModel可以恢复数据又是如何实现的? 现在就让我们一起来分析下它的源码。

源码分析

Viewmodel的创建

首先我们来看下Viewmodel是怎么被创建的。

从上面可以得知,创建Viewmodel的方式是:

 val mainViewModel = ViewModelProvider(this).get(TestViewModel::class.java)

传入class类型,然后得到了ViewModel。看下ViewModelProcider的构造函数:

### ViewModelProvider 
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
  		//得到了ViewModelStore
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

//缓存了ViewModerStore
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

这里我们看到他得到了ViewmodelStore。可以是我们传进去的只是Activity实例,那ViewModelStoreOwner又是什么?

//拥有 ViewModelStore 的范围。
//此接口的实现的职责是在配置更改期间保留拥有的 ViewModelStore,
//并在此范围将被销毁时调用 ViewModelStore.clear()。
public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}

ViewModelStoreOwner是个接口,再来看下ComponentActivity是不是对它进行了实现:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {
          ......
            
      //实现了ViewModelStoreOwner, 重写了getViewModelStore方法
      public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
          //里面内容下面分析
         ....
        return mViewModelStore;
    }
}

原来ComponentActivity实现了ViewModelStoreOwner接口。

回到例子中,ViewModelProvider(this).get(TestViewModel::class.java)中的get方法又做了什么?

### ViewModelProvider
   public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
  	//拿到key, 也就是ViewmodelStore中的Map用于存ViewModel的key
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
  	//获取到ViewModel实例
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            //返回缓存的ViewModel对象
            return (T) viewModel;
        } else {
            if (viewModel != null) {
            }
        }
  	//使用工厂模式创建 ViewModel 实例
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
  	//将创建的 ViewModel 实例放进 mViewModelStore 缓存中
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

先尝试从ViewModelStore获取ViewModel实例,如果没有获取到,就使用Factory创建,创建出的ViewModel最后都会存放到mViewModelStore中,我们再来看下ViewModelStore这个类做了什么:

### ViewModelStore
public class ViewModelStore {
   //内部由HashMap进行存储
    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);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }
  
  	//调用viewModel的clear方法,然后清除ViewModel
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

在ViewModelStore中就做了将viewModel作为value存储到HashMap中。

看了VIewModel是怎么创建出来的,以及实例缓存到那里,再来看下ViewModelStore又是如何创建的。

ViewmodelStore的创建

再次返回到上面getViewModelStore方法里面看下:

### ComponentActiivty   
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
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // 从 NonConfigurationInstances 恢复 ViewModelStore
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

先从NonConfigurationInstances中获取VIewModelStore实例,如果不存在,则会创建一个新的ViewModelSotre。这里我们知道了,创建出的ViewModelStore会缓存到NonConfigurationInstances中。那ViewModelStore又是什么时候缓存进去的。

来看下getLastNonConfigurationInstance方法:

### Activity 
 //先前由 onRetainNonConfigurationInstance() 返回的对象
  /**
     * 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()}
     */
public Object getLastNonConfigurationInstance() {
        return mLastNonConfigurationInstances != null
                ? mLastNonConfigurationInstances.activity : null;
    }

通过上面注释可以知道mLastNonConfigurationInstances是由onRetainNonConfigurationInstance返回的。

onRetainNonConfigurationInstance又是在什么时候被调用的?最终被我们找到了:

###ActivityThread
void performDestroyActivity(ActivityClientRecord r, boolean finishing,
            int configChanges, boolean getNonConfigInstance, String reason) {
       ......
      if (getNonConfigInstance) {
                try {
                    r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
                } catch (Exception e) {
                    if (!mInstrumentation.onException(r.activity, e)) {
                        throw new RuntimeException("Unable to retain activity "
                                + r.intent.getComponent().toShortString() + ": " + e.toString(), e);
                    }
                }
            }
        ......
}

performDestroyActivity方法中会被调用,可以看到onRetainNonConfigurationInstance方法返回的Object会赋值给ActivityClientRecordlastNonConfigurationInstances,这样子就保存了下来。再来看下onRetainNonConfigurationInstance方法。

### ComponetActivity    
  //配置发生更改的时候调用
  //保留所有适当的非配置状态
public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            //没有人调用 getViewModelStore(),所以看看我们上一个 NonConfigurationInstance 中是否存在现					//有的 ViewModelStore
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }
				
  	//创建 NonConfigurationInstances 对象,并赋值 viewModelStore
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

到这里我们知道了,Activity在应为配置发生更改销毁重建的时候会调用onRetainNonConfigurationInstance将ViewModelStore实例保存到NonConfigurationInstances中。之后再重建的时候就可以通过getLastNonConfigurationInstance方法来获取之前缓存的ViewModelStore实例。

NonConfigurationInstances又是什么,怎么可以在销毁重建的时候还一直保留?来看下NonConfigurationInstances保存在哪里,先看下在哪里被赋值的。

### Activity
  final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
            IBinder shareableActivityToken) {
  
  ......
    //在attach方法中会进行赋值
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
  ......
}

mLastNonConfigurationInstances是在Activity的attach方法中赋值。


### ActivityThread

  private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
			······
        //由ActivityClientRecord中获得
        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.configCallback,
                        r.assistToken, r.shareableActivityToken);
  ......
}

ActivityperformLaunchActivity方法中,可以看到lastNonConfigurationInstances是保存在ActivityClientRecord中的。

又因为界面在销毁的时候调用performDestroyActivity方法,内部又会调用ActivityretainNonConfigurationInstances方法将lastNonConfigurationInstances缓存到ActivityClientRecord中,也就是存到应用本身的进程中了。

所以页面在销毁重建的时候,保存在ActivityClientRecord中的lastNonConfigurationInstances是不会受到影响的。

到这里我们也知道在Activity因配置更改重建后ViewModel依然存在的原因了。

ViewModel的销毁

我们已经知道了,在ViewmodelStore中会调用viewmodle的clear方法。

###ViewModelStore
public class ViewModelStore {

  ......
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

遍历缓存中viewmodel依次调用,那ViewModelStore的clear方法又是什么时候调用的?

### ComponentActivity
public ComponentActivity() {
  	......
      getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
              //activity生命周期处于destory状态
                if (event == Lifecycle.Event.ON_DESTROY) {
                  //非配置发生改变
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });
}

这里我们看到调用ViewModelStore中的clear方法被调用的条件首先要观察当前的生命周期处于DESTORY,另外检测因为Configurations的改变而销毁的。

所以在 activity 销毁时,判断如果是非配置改变导致的销毁, getViewModelStore().clear() 才会被调用。

viewModelScope了解吗

viewModelScope 是一个 ViewModel 的 Kotlin 扩展属性。它能在ViewModel销毁时 (onCleared() 方法调用时) 退出。那它又是什么时候关闭的?

我们还是来看下它的实现:

//CoroutineScope 绑定到这个 ViewModel。当 ViewModel 被清除时,这个范围将被取消,即调用 //ViewModel.onCleared 这个范围绑定到 Dispatchers.Main.immediate
val ViewModel.viewModelScope: CoroutineScope
        get() {
            val scope: CoroutineScope? = this.getTag(JOB_KEY)
            if (scope != null) {
                return scope
            }
          // 未命中缓存,则通过 setTagIfAbsent() 添加到 ViewModel 中
            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()
    }
}

根据注释可以得知,Viewmoel被清除的时候,就是调用ViewModel的onClear方法时,就会取消作用域。而ViewModel的清除又是为什么会让其关闭?

再让我们看下Viewmodel的clear方法:

### ViewModel
 //当不再使用此ViewModel并将其销毁时,将调用此方法。
 protected void onCleared() {
    }

 final void clear() {
        mCleared = true;
        //由于 clear() 是最终的,因此仍会在模拟对象上调用此方法,并且在这些情况下,mBagOfTags 为空。它总是空
  //的,因为 setTagIfAbsent 和 getTag 不是最终的,所以我们可以跳过清除它
        if (mBagOfTags != null) {
            synchronized (mBagOfTags) {
                for (Object value : mBagOfTags.values()) {
                    // see comment for the similar call in setTagIfAbsent
                    closeWithRuntimeException(value);
                }
            }
        }
        onCleared();
    }

怎么onClear方法是空实现?又看到这个方法是被clear方法所调用,我们再来看下mbagofTags是什么东西?

private final Map<String, Object> mBagOfTags = new HashMap<>();

这是个Map对象,再继续往下找可以看到调用setTagIfAbsent进行了赋值。

 <T> T setTagIfAbsent(String key, T newValue) {
        T previous;
        synchronized (mBagOfTags) {
            previous = (T) mBagOfTags.get(key);
            if (previous == null) {
              //如果之前没有保存则放入map中
                mBagOfTags.put(key, newValue);
            }
        }
        T result = previous == null ? newValue : previous;
   			//// 如果此 viewModel 被标记清除
        if (mCleared) {
            closeWithRuntimeException(result);
        }
        return result;
    }

这个setTagIfAbsent方法不就是在viewModelScope第一次被创建的时候调用的,也就是在这里将对象添加到ViewModel中。

好了再来回顾下,viewModelScope 第一次被调用时,会调用 setTagIfAbsent(JOB_KEY,CloseableCoroutineScope)进行缓存。

看下CloseableCoroutineScope 类,实现了 Closeable 接口,并且在 close() 中进行了协程作用域coroutineContext对象的取消操作。

总结

我们先介绍了viewmodel的背景,了解到它的特点:因配置更改界面销毁重建后依然存在、不持有UI应用,也介绍了ViewModel的基本使用。最后大篇幅的分析了ViewModel几个关键的核心原理。

到这里,我们的分析之旅也结束了~

参考

ViewModel官网

Android - ViewModel总结

<think>好的,我现在需要帮助用户理解ViewModel源码原理,尤其是Android Jetpack中的ViewModel组件。用户已经提供了一些相关的引用内容,我需要结合这些内容,并参考之前的回答结构来组织信息。 首先,我应该回顾用户之前的问题和回答,看看有没有可以借鉴的结构。之前的回答关于RecyclerView的优化非常详细,分成了几个核心原因、优化方案、其他优化点等部分。类似的,ViewModel的解析也可以分成几个主要部分,比如整体设计、关键源码分析、生命周期管理、数据保持机制等。 接下来,我需要查看用户提供的引用内容。引用[1]提到ViewModelAndroid Jetpack架构组件的一部分,引用[2]和[3]涉及ViewModel的实例检索和工厂模式,引用[4]是关于Factory接口,引用[5]提到了LiveData和生命周期的关系。这些引用可能帮助我解释ViewModel的工作原理,尤其是工厂模式和生命周期绑定。 然后,我需要明确ViewModel核心功能:数据管理、生命周期感知、配置变化时的数据保持。用户可能想知道ViewModel是如何实现这些功能的,特别是在源码层面。 首先,ViewModel的整体设计可能涉及ViewModelStore和ViewModelProvider。ViewModelStore负责存储ViewModel实例,ViewModelProvider负责创建和管理这些实例。需要解释ViewModelStoreOwner接口的作用,以及Activity或Fragment如何实现这个接口来持有ViewModelStore。 接下来,ViewModel的创建过程,可能涉及Factory模式。用户提供的引用[3]和[4]提到Factory接口,用于实例化ViewModel。需要说明默认工厂如何工作,比如SavedStateViewModelFactory,以及如何通过反射或自定义Factory来创建实例。 然后,ViewModel的生命周期管理。需要解释ViewModel是如何与Lifecycle组件集成的,确保在配置变化时不被销毁,并在适当的时机清除。引用[5]提到LiveData与生命周期的关系,ViewModel可能也利用了类似的机制。 数据保持机制方面,ViewModel在屏幕旋转等配置变化时保持数据,这是因为ViewModelStore由Activity的非配置保留实例(如Activity的onRetainNonConfigurationInstance()方法)保存。需要说明源码中如何实现这一点,比如ComponentActivity中的ViewModelStore维护。 可能还需要提到SavedStateHandle,用于在进程重建时恢复数据,结合引用[2]中的SavedStateViewModel。 在分析源码时,需要指出关键类和方法,比如ViewModelProvider的构造方法,如何获取Factory,ViewModelStore的存储结构(如HashMap),以及ComponentActivity如何维护ViewModelStore。 此外,需要注意线程安全问题,ViewModel的实例化是否在主线程,以及如何确保线程安全。 最后,用户可能有后续问题,比如如何自定义ViewModelFactory,ViewModel与LiveData的配合使用,或者生命周期绑定的具体实现。需要在相关问题中预先考虑这些点。 现在需要将这些思考整理成一个结构清晰的回答,分点解析源码原理,并引用提供的资料来支持论点,同时保持语言的中文和逻辑连贯。</think>### ViewModel 源码原理深度解析 --- #### 一、ViewModel核心设计目标 1. **数据与 UI 解耦** ViewModel 将业务逻辑从 Activity/Fragment 中剥离,避免因配置变化(如屏幕旋转)导致的数据丢失[^1]。 2. **生命周期感知** 与宿主(Activity/Fragment)生命周期绑定,自动清理资源,防止内存泄漏[^1]。 3. **数据持久化** 在配置变化时保留数据,通过 `ViewModelStore` 实现跨生命周期存储[^3]。 --- #### 二、ViewModel 核心源码结构 ##### 1. **ViewModelStore:数据存储中心** - **存储结构**:内部通过 `HashMap<String, ViewModel>` 缓存所有 ViewModel 实例 ```java public class ViewModelStore { private final HashMap<String, ViewModel> mMap = new HashMap<>(); // 通过 key(自定义或默认类名)存取 ViewModel } ``` - **生命周期绑定**:由 `ComponentActivity` 或 `Fragment` 持有,在 `onDestroy()` 时判断是否需要清除 ```java // ComponentActivity 源码 public final Object onRetainNonConfigurationInstance() { // 配置变化时保留 ViewModelStore ViewModelStore viewModelStore = mViewModelStore; return new NonConfigurationInstances(..., viewModelStore); } ``` ##### 2. **ViewModelProvider:实例化控制器** - **工厂模式**:通过 `Factory` 接口实现灵活创建(默认支持反射或 SavedState 扩展)[^4] ```java public interface Factory { <T extends ViewModel> T create(@NonNull Class<T> modelClass); } ``` - **创建流程**: 1. 检查 `ViewModelStore` 中是否存在缓存 2. 若不存在,通过 `Factory` 创建新实例并存储 ```java // ViewModelProvider 源码关键逻辑 public <T extends ViewModel> T get(@NonNull Class<T> modelClass) { String key = DEFAULT_KEY + ":" + modelClass.getCanonicalName(); ViewModel viewModel = mViewModelStore.get(key); if (modelClass.isInstance(viewModel)) { return (T) viewModel; } else { viewModel = mFactory.create(modelClass); mViewModelStore.put(key, viewModel); return (T) viewModel; } } ``` ##### 3. **SavedStateHandle:数据恢复机制** - **进程重建支持**:通过 `SavedStateViewModelFactory` 注入 `SavedStateHandle`,实现 `onSaveInstanceState()` 的自动化管理[^2] ```kotlin class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { val data: MutableLiveData<String> = state.getLiveData("key") } ``` --- #### 三、ViewModel 生命周期管理源码解析 ##### 1. **与 Lifecycle 的集成** - **观察者注册**:在 `ComponentActivity` 中通过 `Lifecycle` 监听生命周期状态 ```java getLifecycle().addObserver(new LifecycleEventObserver() { @Override public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) { if (event == Lifecycle.Event.ON_DESTROY) { if (!isChangingConfigurations()) { mViewModelStore.clear(); // 非配置变化时清理所有 ViewModel } } } }); ``` ##### 2. **清理机制** - **自动释放**:当 Activity/Fragment 永久销毁时(非配置变化),触发 `ViewModel.onCleared()` ```java public class ViewModel { protected void onCleared() { // 子类可重写此方法释放资源(如取消网络请求) } } ``` --- #### 四、关键设计模式与线程安全 1. **工厂模式** - 默认使用 `NewInstanceFactory` 反射创建实例,或通过自定义 `Factory` 控制构建过程[^4]。 2. **单例特性** - 每个 ViewModel 类在同一个 `ViewModelStore` 中仅存在一个实例(通过 `key` 唯一标识)。 3. **线程安全** - `ViewModelStore` 和 `ViewModelProvider` 的操作通过主线程执行保证线程安全。 --- #### 五、典型使用场景源码分析 ##### 1. 通过 `by viewModels()` 获取实例 ```kotlin val viewModel: MyViewModel by viewModels() // 委托扩展函数内部调用 ViewModelProvider ``` - **源码链路**: `viewModels()` → `ViewModelLazy` → `ViewModelProvider.get()` ##### 2. 自定义 Factory ```kotlin val viewModel: MyViewModel by viewModels { MyFactory(...) } ``` - **实现原理**: 通过 `ViewModelProvider.Factory` 接口注入依赖(如数据库访问对象)。 --- ### 相关问题 1. **ViewModel 如何避免内存泄漏?** ViewModel 不持有 UI 层引用,且通过 `onCleared()` 主动释放资源[^1]。 2. **如何在 ViewModel 中处理 SavedState?** 使用 `SavedStateHandle` 存取数据,支持进程重建恢复[^2]。 3. **ViewModel 与 LiveData 如何配合使用?** ViewModel 持有 `LiveData` 暴露数据,结合观察者模式实现数据驱动 UI[^5]。 --- 通过源码分析可见,ViewModel 通过**存储隔离**、**工厂模式**和**生命周期绑定**三大机制,实现了数据持久化与安全管理的核心目标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值