ViewModel能够在系统配置发生变化时,跨越Activity的生命周期,其实质是在旧Activity即将销毁时,通过NonConfigurationInstances将ViewModel挂载到 ActivityClientRecord上
重建的新Activity与销毁的旧Activity是共用同一个ActivityClientRecord实例
在重建新Activity时,会从ActivityClientRecord中取出旧Activity销毁之前保存的NonConfigurationInstances
1、旧Activity的销毁
1.1、AMS重建Activity时,会传入该Activity的token。这样,在应用进程中就可以通过这个token获取到保存在mActivities中的ActivityClientRecord
@Override
public void handleRelaunchActivity(@NonNull ActivityClientRecord tmp,
@NonNull PendingTransactionActions pendingActions) {
......
ActivityClientRecord r = mActivities.get(tmp.token);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
if (r == null) {
return;
}
r.activity.mConfigChangeFlags |= configChanges;
r.mPreserveWindow = r.activity.mWindowAdded && tmp.mPreserveWindow;
r.activity.mChangingConfigurations = true;
handleRelaunchActivityInner(r, tmp.pendingResults, tmp.pendingIntents,
pendingActions, tmp.startsNotResumed, tmp.overrideConfig, tmp.mActivityWindowInfo,
"handleRelaunchActivity");
}
1.2、在重建新Activity之前,会先将失效的旧Activity销毁。同时,将ActivityClientRecord对应的字段置空,待新Activity创建完成后,再将该字段重新赋值为新Activity
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) {
// Preserve last used intent, it may be set from Activity#setIntent().
final Intent customIntent = r.activity.mIntent;
// Need to ensure state is saved.
if (!r.paused) {
performPauseActivity(r, false, reason, null /* pendingActions */);
}
if (!r.stopped) {
callActivityOnStop(r, true /* saveState */, reason);
}
handleDestroyActivity(r, false /* finishing */, true /* getNonConfigInstance */, reason);
r.activity = null;
r.window = null;
r.hideForNow = false;
// Merge any pending results and pending intents; don't just replace them
if (pendingResults != null) {
if (r.pendingResults == null) {
r.pendingResults = pendingResults;
} else {
r.pendingResults.addAll(pendingResults);
}
}
if (pendingIntents != null) {
if (r.pendingIntents == null) {
r.pendingIntents = pendingIntents;
} else {
r.pendingIntents.addAll(pendingIntents);
}
}
r.startsNotResumed = startsNotResumed;
r.overrideConfig = overrideConfig;
r.mActivityWindowInfo.set(activityWindowInfo);
handleLaunchActivity(r, pendingActions, mLastReportedDeviceId, customIntent);
}
1.3、在销毁旧Activity之前,会对传入的getNonConfigInstance变量进行判断。若为真,则调用Activity的retainNonConfigurationInstances()方法, 收集需要保存的状态信息, 将其何存至Activity对应的ActivityClientRecord对象的android.app.Activity.NonConfigurationInstances类型的数据成员中
/** Core implementation of activity destroy call. */
void performDestroyActivity(ActivityClientRecord r, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
Class<? extends Activity> activityClass = null;
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
activityClass = r.activity.getClass();
r.activity.mConfigChangeFlags |= configChanges;
if (finishing) {
r.activity.mFinished = true;
}
performPauseActivityIfNeeded(r, "destroy");
if (!r.stopped) {
callActivityOnStop(r, false /* saveState */, "destroy");
}
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);
}
}
}
......
}
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;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
2、新Activity的创建
2.1、在新创建Activity的attach()方法中,传入之前保存的android.app.Activity.NonConfigurationInstances
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
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) {
......
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
......
}
2.2、在新创建的Activity中获取ViewModelStore时,如果mViewModelStore数据成员为空,则会通过getLastNonConfigurationInstance()方法,从之前恢复的android.app.Activity.NonConfigurationInstances中,获取androidx.activity.ComponentActivity.NonConfigurationInstances
@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.");
}
ensureViewModelStore();
return mViewModelStore;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
/**
* 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;
}
3、androidx.activity.ComponentActivity.NonConfigurationInstances与android.app.Activity.NonConfigurationInstances之间的转换
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
3.1、将androidx.activity.ComponentActivity.NonConfigurationInstance保存至android.app.Activity.NonConfigurationInstances类中的activity(位于对象内存模型的最开头)数据成员
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;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
3.2、将android.app.Activity.NonConfigurationInstances类中的activity成员强转成androidx.activity.ComponentActivity.NonConfigurationInstance类型
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
4、ViewModel的销毁
4.1、重建新Activity之前,先将待销毁的旧Activity的mChangingConfigurations变量置为true。随后,依次执行旧Activity的onPause()、onStop()、onDestroy()。
@Override
public void handleRelaunchActivity(@NonNull ActivityClientRecord tmp,
@NonNull PendingTransactionActions pendingActions) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
......
r.activity.mConfigChangeFlags |= configChanges;
r.mPreserveWindow = r.activity.mWindowAdded && tmp.mPreserveWindow;
r.activity.mChangingConfigurations = true;
......
}
4.2、只有当Activity不是在配置发生变化,而引起重建的情况下,ViewModel才会在Activity销毁时,进行clear操作。否则,不会跟随Activity销毁进行clear操作
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});