一、Android Jetpack简介
Android
官网对Jetpack
的介绍如下:
Jetpack is a suite of libraries to help developers follow best practices, reduce boilerplate code, and write code that works consistently across Android versions and devices so that developers can focus on the code they care about.
可见Jetpack
是一个由多个库组成的套件,使用这个套件可以帮助开发者:
- 遵循最佳实践:
Jetpack
提供的组件基于最新的设计方法构建,可以减少崩溃和内存泄漏等问题的出现; - 减少样板代码:
Jetpack
提供的组件提供对繁琐的生命周期、后台任务的管理,帮助开发者实现可维护的代码; - 减少差异:实现在不同版本和设备上表现一致的应用,开发者可以集中精力编写对他们来说真正重要的代码,而不是各种版本兼容的代码。
Android
官网上对Jetpack
组成部分的分类如下图所示(最新官网无下图):
Android
提供的Jetpack
一共分为四个部分:架构、基础、UI
和行为,其中Android Architecture Component
是各个应用使用最多的部分,通常在工程中使用Lifecycle
、LiveData
以及ViewModel
来实现MVVM
架构,因此下面会这三个组件进行分析,《浅析Android Jetpack ACC之Lifecycle》、《浅析Android Jetpack ACC之LiveData》分别对Lifecycle
和LiveData
这两个核心组件进行了分析,本文将对ViewModel
这个视图模型组件进行分析。
二、ViewModel-自动保存/恢复的视图模型
1. 作用目的
ViewModel
组件管理的数据在发生屏幕旋转等配置更改后保留并恢复给后续使用,同时ViewModel
组件无需持有View
层的引用,因为ViewModel
组件主要是为View
提供数据但不负责View
的更新,ViewModel
所扮演的角色与MVP
架构中的Presenter
层相似,但是不会持有View
,数据同步到View
层是借助之前分析过的LiveData
组件,因此简化了View
层与逻辑层之间的依赖关系。
ViewModel
组件支持在发生屏幕旋转等配置更改后保留并恢复,因此ViewModel
的生命周期一般会比Activity
的生命周期要长,两者的生命周期对比如下图所示。
总结来说,ViewModel
组件是一个支持自动保存/恢复的视图模型类,通常结合LiveData
组件实现无需持有View
层,即可完成数据同步到View
层的目的。此外,ViewModel
组件支持在同一个Activity
下的多个Fragment
之间共享数据,这样就可以实现Fragment
之间的相互通信。
2. 使用示例
ViewModel
组件一般会搭配LiveData
组件一起使用,分为以下步骤:
- 继承
ViewModel
类定义自己的ViewModel
类(如LocationViewModel
类) Activity/Fragment
通过ViewModelProvider
获取自定义的ViewModel
实例(如LocationViewModel
)- 通过观察自定义的
ViewModel
(如LocationViewModel
)中的LiveData
实现UI
更新逻辑
// 1. 自定义ViewModel
class LocationViewModel : ViewModel() {
private val locationData = MutableLiveData<LocationImpl.Location>()
fun locationData(): LiveData<LocationImpl.Location> {
return locationData
}
fun startLocation() {
LocationImpl.startLocation(object : LocationImpl.LocationListener {
override fun onLocationChanged(location: LocationImpl.Location) {
locationData.postValue(location)
}
})
}
fun stopLocation() {
// stop locate on worker thread
LocationImpl.stopLocation()
}
}
class MVVMLocationActivity : ComponentActivity(), IView {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_location)
// 2. 使用ViewModelProvider获取LocationViewModel实例
val locationViewModel = ViewModelProvider(this).get(LocationViewModel::class.java)
// 3. 观察LiveData并在数据变化时刷新UI
locationViewModel.locationData().observe(this) { location ->
updateLocation(location)
}
}
override fun updateLocation(location: LocationImpl.Location) {
// update location
}
}
通过示例代码可以发现,使用ViewModel
以及LiveData
组件之后,View
层与业务层(MVC
中的Controller
层、MVP
中的Presenter
层)之间的依赖关系简化了,ViewModel
没有持有View
的引用,代码可维护性大大提高。
2. 实现原理
介绍完使用方式之后,但是对于ViewModel
如何在发生屏幕旋转等配置更改后依然可以保留并用于后续新的Activity
实例,以及如何在多个Fragment
之间共享同一个ViewModel
,依然还是不清楚,下面就从源码层面分析下这是如何实现的。
目前关于ViewModel
只有提到获取方式,那么先从ViewModel
实例的获取开始分析:
2.1 ViewModel实例的获取
获取ViewModel
实例之前需要构造ViewModelProvider
实例,然后调用ViewModelProvider#get
方法才能获取ViewModel
实例,先看下ViewModelProvider
的构造函数,然后再看下ViewModelProvider#get
方法的实现。
public actual open class ViewModelProvider private constructor(
private val impl: ViewModelProviderImpl, // 真正的Provider
) {
public constructor(
owner: ViewModelStoreOwner,
) : this(
store = owner.viewModelStore, //
factory = ViewModelProviders.getDefaultFactory(owner),
defaultCreationExtras = ViewModelProviders.getDefaultCreationExtras(owner)
)
@JvmOverloads
public constructor(
store: ViewModelStore,
factory: Factory,
defaultCreationExtras: CreationExtras = CreationExtras.Empty,
) : this(ViewModelProviderImpl(store, factory, defaultCreationExtras))
}
internal object ViewModelProviders {
internal fun getDefaultFactory(owner: ViewModelStoreOwner): ViewModelProvider.Factory =
if (owner is HasDefaultViewModelProviderFactory) {
owner.defaultViewModelProviderFactory
} else {
DefaultViewModelProviderFactory
}
}
public interface ViewModelStoreOwner {
/**
* The owned [ViewModelStore]
*/
public val viewModelStore: ViewModelStore
}
在创建ViewModelProvider
对象时将ComponentActivity
对象传入了构造函数时,而ComponentActivity
类实现了ViewModelStoreOwner
接口,ViewModelStoreOwner
接口内部只定义了一个抽象属性,因此看下ComponentActivity
类是如何重写这个抽象属性的访问方法的。
open class ComponentActivity() :
androidx.core.app.ComponentActivity(),
ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner,
ActivityResultRegistryOwner,
ActivityResultCaller,
OnConfigurationChangedProvider,
OnTrimMemoryProvider,
OnNewIntentProvider,
OnMultiWindowModeChangedProvider,
OnPictureInPictureModeChangedProvider,
OnUserLeaveHintProvider,
MenuHost,
FullyDrawnReporterOwner {
override val defaultViewModelProviderFactory: ViewModelProvider.Factory by lazy {
SavedStateViewModelFactory(application, this, if (intent != null) intent.extras else null)
}
internal class NonConfigurationInstances {
var custom: Any? = null
var viewModelStore: ViewModelStore? = null
}
override val viewModelStore: ViewModelStore
/**
* Returns the [ViewModelStore] associated with this activity
*
* Overriding this method is no longer supported and this method will be made `final` in a
* future version of ComponentActivity.
*
* @return a [ViewModelStore]
* @throws IllegalStateException if called before the Activity is attached to the
* Application instance i.e., before onCreate()
*/
get() {
checkNotNull(application) {
("Your activity is not yet attached to the " +
"Application instance. You can't request ViewModel before onCreate call.")
}
ensureViewModelStore()
return _viewModelStore!!
}
private fun ensureViewModelStore() {
if (_viewModelStore == null) {
val nc = lastNonConfigurationInstance as NonConfigurationInstances?
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
_viewModelStore = nc.viewModelStore
}
if (_viewModelStore == null) {
_viewModelStore = ViewModelStore()
}
}
}
}
可以看到获取viewModelStore
属性的值会间接调用ComponentActivity#ensureViewModelStore
方法为ComponentActivity
的成员变量_viewModelStore
进行初始化,注意这里出现了NonConfigurationInstances
实例(NonConfigurationInstances
是ComponentActivity
类的一个内部类),如果存在NonConfigurationInstances
将会先尝试从这个实例中获取ViewModelStore
对象,获取不到或者不存在NonConfigurationInstances
实例将会直接构造一个ViewModelStore
对象。因此可以猜想ViewModelStore
对象可能是借助NonConfigurationInstances
实例进行保存和恢复的。
ComponentActivity
的成员变量_viewModelStore
只会通过ComponentActivity#ensureViewModelStore
方法对其进行赋值,因此看下ComponentActivity#ensureViewModelStore
方法的调用点,发现除了viewModelStore
属性的访问方法会调用之外,只剩下ComponentActivity
的初始化代码块中调用了,具体的代码如下:
open class ComponentActivity() :
androidx.core.app.ComponentActivity(),
ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner,
ActivityResultRegistryOwner,
ActivityResultCaller,
OnConfigurationChangedProvider,
OnTrimMemoryProvider,
OnNewIntentProvider,
OnMultiWindowModeChangedProvider,
OnPictureInPictureModeChangedProvider,
OnUserLeaveHintProvider,
MenuHost,
FullyDrawnReporterOwner {
init {
// ...
@Suppress("LeakingThis")
lifecycle.addObserver(
object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
ensureViewModelStore()
lifecycle.removeObserver(this)
}
}
)
// ...
}
override val lifecycle: Lifecycle
get() = super.lifecycle // 返回父类中的lifecycleRegistry变量
}
可以看到,在ComponentActivity
的生命周期发生变化时会调用onStateChanged
方法,进一步会调用ComponentActivity#ensureViewModelStore
方法,因此在ComponentActivity
重建之后也会调用到ComponentActivity#ensureViewModelStore
方法对成员变量_viewModelStore
进行赋值。
至此,明确了ComponentActivity
对象的成员变量_viewModelStore
对应ViewModelProviderImpl
对象中的成员store
。下面接着看下ViewModelProvider#get
方法是如何返回自定义ViewModel
的实例的。
public actual open class ViewModelProvider private constructor(
private val impl: ViewModelProviderImpl,
) {
@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T =
get(modelClass.kotlin)
@MainThread
public actual operator fun <T : ViewModel> get(modelClass: KClass<T>): T =
impl.getViewModel(modelClass)
}
internal class ViewModelProviderImpl(
private val store: ViewModelStore,
private val factory: ViewModelProvider.Factory,
private val extras: CreationExtras,
) {
constructor(
owner: ViewModelStoreOwner,
factory: ViewModelProvider.Factory,
extras: CreationExtras,
) : this(owner.viewModelStore, factory, extras)
@Suppress("UNCHECKED_CAST")
internal fun <T : ViewModel> getViewModel(
modelClass: KClass<T>,
key: String = ViewModelProviders.getDefaultKey(modelClass),
): T {
// 先从ViewModelStore中查找是否存在缓存
val viewModel = store[key]
// 接着判断缓存对象(如果有)的类型是否和待返回的自定义ViewModel类的类型一致,一致的话直接返回
if (modelClass.isInstance(viewModel)) {
if (factory is ViewModelProvider.OnRequeryFactory) {
factory.onRequery(viewModel!!)
}
return viewModel as T
} else {
@Suppress("ControlFlowWithEmptyBody") if (viewModel != null) {
// TODO: log a warning.
}
}
val extras = MutableCreationExtras(extras)
extras[ViewModelProviders.ViewModelKey] = key
// 缓存中不存在自定义ViewModel类型的对象,直接创建对象并缓存到ViewModelStore中,之后直接返回新创建的对象
return createViewModel(factory, modelClass, extras).also { vm -> store.put(key, vm) }
}
}
internal actual fun <VM : ViewModel> createViewModel(
factory: ViewModelProvider.Factory,
modelClass: KClass<VM>,
extras: CreationExtras
): VM {
// Android targets using `compileOnly` dependencies may encounter AGP desugaring
// issues where `Factory.create` throws an `AbstractMethodError`. This is resolved by an
// Android-specific implementation that first attempts all `ViewModelProvider.Factory.create`
// method overloads before allowing the exception to propagate.
// (See b/230454566 and b/341792251 for more details).
return try {
factory.create(modelClass, extras)
} catch (e: AbstractMethodError) {
try {
factory.create(modelClass.java, extras)
} catch (e: AbstractMethodError) {
factory.create(modelClass.java)
}
}
}
可以看到会先从ViewModelStore
查找之前是否创建过同一类型的对象,如果创建过则直接返回缓存对象,否则调用factory
创建自定义ViewModel
类型的对象,将其缓存到ViewModelStore
中后直接返回。factory
的类型是SavedStateViewModelFactory
,通过SavedStateViewModelFactory#create
方法可以看出最终通过反射创建了自定义ViewModel
类型的对象。
class SavedStateViewModelFactory : ViewModelProvider.OnRequeryFactory, ViewModelProvider.Factory {
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 {
val viewModel = if (lifecycle != null) {
create(key, modelClass)
} else {
throw IllegalStateException("SAVED_STATE_REGISTRY_OWNER_KEY and" +
"VIEW_MODEL_STORE_OWNER_KEY must be provided in the creation extras to" +
"successfully create a ViewModel.")
}
viewModel
}
}
}
到这里基本上梳理出ViewModel
实例的获取过程:先通过ViewModelStore
对象从缓存中尝试获取已创建的自定义ViewModel
类型的对象,没有找到则通过反射创建自定义ViewModel
类型的对象。可见,如果没有ViewModelStore
的存在那么每次都会重新创建ViewModel
实例,也就无法在旋转屏幕后还可以继续使用之前创建的ViewModel
实例了。因此,下面重点看下ViewModelStore
实例是如何在旋转屏幕之后还可以保留下来继续使用的。
2.2 ViewModelStore实例的获取
在2.1
节分析ViewModel
实例的获取时,发现在ComponentActivity
类的初始化代码块中会监听生命周期的变化,并在生命周期发生变化时调用ComponentActivity#ensureViewModelStore
方法对_viewModelStore
成员变量进行赋值。
open class ComponentActivity() :
androidx.core.app.ComponentActivity(),
ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner,
ActivityResultRegistryOwner,
ActivityResultCaller,
OnConfigurationChangedProvider,
OnTrimMemoryProvider,
OnNewIntentProvider,
OnMultiWindowModeChangedProvider,
OnPictureInPictureModeChangedProvider,
OnUserLeaveHintProvider,
MenuHost,
FullyDrawnReporterOwner {
init {
// ...
@Suppress("LeakingThis")
lifecycle.addObserver(
object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
ensureViewModelStore()
lifecycle.removeObserver(this)
}
}
)
// ...
}
override val lifecycle: Lifecycle
get() = super.lifecycle // 返回父类中的lifecycleRegistry变量
private fun ensureViewModelStore() {
if (_viewModelStore == null) {
val nc = lastNonConfigurationInstance as NonConfigurationInstances?
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
_viewModelStore = nc.viewModelStore
}
if (_viewModelStore == null) {
_viewModelStore = ViewModelStore()
}
}
}
}
可以看到在创建ViewModelStore
实例之前会尝试调用Activity#getLastNonConfigurationInstance
方法获取NonConfigurationInstances
实例,而NonConfigurationInstances
实例是在ComponentActivity#onRetainNonConfigurationInstance
方法中创建并保存的。
open class ComponentActivity() :
androidx.core.app.ComponentActivity(),
ContextAware,
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner,
ActivityResultRegistryOwner,
ActivityResultCaller,
OnConfigurationChangedProvider,
OnTrimMemoryProvider,
OnNewIntentProvider,
OnMultiWindowModeChangedProvider,
OnPictureInPictureModeChangedProvider,
OnUserLeaveHintProvider,
MenuHost,
FullyDrawnReporterOwner {
@Suppress("deprecation")
final override fun onRetainNonConfigurationInstance(): Any? {
// Maintain backward compatibility.
val custom = onRetainCustomNonConfigurationInstance()
var viewModelStore = _viewModelStore
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
val nc = lastNonConfigurationInstance as NonConfigurationInstances?
if (nc != null) {
viewModelStore = nc.viewModelStore
}
}
if (viewModelStore == null && custom == null) {
return null
}
val nci = NonConfigurationInstances()
nci.custom = custom
nci.viewModelStore = viewModelStore
return nci
}
}
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback,
ContentCaptureManager.ContentCaptureClient {
/**
* 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() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
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, IBinder initialCallerInfoAccessToken) {
...
attachBaseContext(context);
...
mLastNonConfigurationInstances = lastNonConfigurationInstances;
...
}
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
}
从ComponentActivity#onRetainNonConfigurationInstance
方法可以看出,会将当前的_viewModelStore
变量和ComponentActivity#onRetainCustomNonConfigurationInstance
方法返回的对象保存到NonConfigurationInstances
对象中。而Activity#onRetainNonConfigurationInstance
方法会在什么时候调用,推测应该是新的Activity
实例创建之前调用,这个下面会从源码层面进行确认。先看下Activity#getLastNonConfigurationInstance
方法获取NonConfigurationInstances
实例是在哪里赋值的,从Activity#getLastNonConfigurationInstance
方法中可以发现返回结果是从Activity#mLastNonConfigurationInstances
中获取的,对应Activity
的静态内部类NonConfigurationInstances
的成员变量activity
,既然是从Activity#mLastNonConfigurationInstances
中获取的,那么看下Activity#mLastNonConfigurationInstances
是在哪里赋值的,从源码寻找发现是在Activity#attach
方法中赋值的。了解过Activity
的启动流程的同学应该知道,在创建完Activity
实例之后紧接着会调用Activity#attach
方法,之后才会调用Activity#onCreate
等生命周期方法。
回顾一下Activity
的启动流程,
public final class ActivityThread extends ClientTransactionHandler implements ActivityThreadInternal {
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
java.lang.ClassLoader cl;
if (isSandboxedSdkContextUsed) {
// In case of sandbox activity, the context refers to the an SDK with no visibility
// on the SandboxedActivity java class, the App context should be used instead.
cl = activityBaseContext.getApplicationContext().getClassLoader();
} else {
cl = activityBaseContext.getClassLoader();
}
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
try {
...
if (activity != null) {
...
activityBaseContext.setOuterContext(activity);
activity.attach(activityBaseContext, 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, r.initialCallerInfoAccessToken);
...
}
}
}
}
从ActivityThread#performLaunchActivity
方法的实现可以发现,Activity#attach
方法中的入参lastNonConfigurationInstances
的值对应r.lastNonConfigurationInstances
,而r
就是ActivityThread#performLaunchActivity
方法的类型为ActivityClientRecord
的入参。因此需要再往前看下这个入参的值来自哪里,
public final class ActivityThread extends ClientTransactionHandler
implements ActivityThreadInternal {
@Override
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, int deviceId, Intent customIntent) {
...
final Activity a = performLaunchActivity(r, customIntent);
...
}
private void handleRelaunchActivityInner(@NonNull ActivityClientRecord r, @Nullable List<ResultInfo> pendingResults, @Nullable List<ReferrerIntent> pendingIntents, @NonNull PendingTransactionActions pendingActions, boolean startsNotResumed, @NonNull Configuration overrideConfig, @NonNull ActivityWindowInfo activityWindowInfo, @NonNull String reason) {
...
handleDestroyActivity(r, false /* finishing */, true /* getNonConfigInstance */, reason);
...
handleLaunchActivity(r, pendingActions, mLastReportedDeviceId, customIntent);
}
@Override
public void handleRelaunchActivity(@NonNull ActivityClientRecord tmp, @NonNull PendingTransactionActions pendingActions) {
...
handleRelaunchActivityInner(r, tmp.pendingResults, tmp.pendingIntents, pendingActions, tmp.startsNotResumed, tmp.overrideConfig, tmp.mActivityWindowInfo, "handleRelaunchActivity");
}
// 在App进程收到RELAUNCH_ACTIVITY消息之后执行此方法
public void handleRelaunchActivityLocally(IBinder token) {
final ActivityClientRecord r = mActivities.get(token);
...
// ActivityRelaunchItem封装了重新启动Activity的逻辑,最终会调用到handleRelaunchActivity
final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain(r.token, null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */, mergedConfiguration, r.mPreserveWindow, r.getActivityWindowInfo());
// Make sure to match the existing lifecycle state in the end of the transaction.
final ActivityLifecycleItem lifecycleRequest = TransactionExecutorHelper.getLifecycleRequestForCurrentState(r);
// Schedule the transaction.
final ClientTransaction transaction = ClientTransaction.obtain(mAppThread);
transaction.addTransactionItem(activityRelaunchItem);
transaction.addTransactionItem(lifecycleRequest);
executeTransaction(transaction);
}
void performDestroyActivity(ActivityClientRecord r, boolean finishing, 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);
}
}
}
...
}
@Override
public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, boolean getNonConfigInstance, String reason) {
performDestroyActivity(r, finishing, getNonConfigInstance, reason);
...
}
}
public class ActivityRelaunchItem extends ActivityTransactionItem {
@Override
public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
@NonNull PendingTransactionActions pendingActions) {
if (mActivityClientRecord == null) {
if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled");
return;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
client.handleRelaunchActivity(mActivityClientRecord, pendingActions);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
向前回溯发现,当调用ActivityThread#handleRelaunchActivity
重新启动Activity
时,先调用ActivityThread#handleDestroyActivity
方法销毁原来的Activity
,然后调用ActivityThread#handleLaunchActivity
启动新的Activity
,在销毁旧Activity
时会调用Activity#retainNonConfigurationInstances
方法,进而调用Activity#onRetainNonConfigurationInstance
方法获取到包含ViewModelStore
实例的配置数据,并将其存放到ActivityClientRecord#lastNonConfigurationInstances
中,在新Activity
创建之后通过Activity#attach
方法传递过去并赋值给Activity#mLastNonConfigurationInstances
,这样当新Activity
的生命周期开始之后就会通过注册到LifecycleRegistry
的观察者,间接调用到ComponentActivity#ensureViewModelStore
方法将旧Activity
的ViewModelStore
实例赋值给新Activity
进行使用了。
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback,
ContentCaptureManager.ContentCaptureClient {
NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
// We're already stopped but we've been asked to retain.
// Our fragments are taken care of but we need to mark the loaders for retention.
// In order to do this correctly we need to restart the loaders first before
// handing them off to the next activity.
mFragments.doLoaderStart();
mFragments.doLoaderStop(true);
ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
if (activity == null && children == null && fragments == null && loaders == null
&& mVoiceInteractor == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity; // onRetainNonConfigurationInstance方法返回的数据,其中包含了ViewModelStore实例
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
}
三、总结
通过源码分析之后,明确了ViewModel
是在旧Activity
实例调用onDestroy
方法之前会调用Activity#retainNonConfigurationInstances
将ViewModelStore
实例进行保存,并在新Activity
实例创建之后通过Activity#attach
方法(在Activity#onCreate
方法调用之前)将ViewModelStore
实例传递并赋值给新Activity
实例继续使用,从而保证了ViewModel
实例在横竖屏切换之后依旧能继续使用。