Fork me on GitHub

ViewModel 源代码分析 (三)

  • viewmodel

    • CreationExtras
      ViewModel创建过程中传递额外参数的容器。

    • InitializerViewModelFactory

      ViewModelProvider.Factory接口实现类,使用ViewModelInitializer来创建ViewModel实例。

    • InitializerViewModelFactoryBuilder

      用于构建InitializerViewModelFactory的工具,通常以DSL形式提供。

    • MutableCreationExtras

      可变版本的CreationExtras,允许添加或修改额外参数。

    • ViewModelFactoryDsl

      一个DSL(领域特定语言),用于更声明式地定义如何创建ViewModel。

    • ViewModelInitializer

      用于初始化ViewModel的类,通常与ViewModelFactoryDsl一起使用。

    • InitializerViewModelFactory

      提供了使用InitializerViewModelFactory的Kotlin扩展。

  • AndroidViewModel

    AndroidViewModel是ViewModel的一个子类,它接受应用程序的Application作为上下文,这对于需要访问Application资源的ViewModel特别有用。

  • HasDefaultViewModelProviderFactory

    一个接口,标识一个类拥有默认的ViewModelProvider.Factory,用于创建ViewModel。

  • ViewModel

  • ViewModelLazy

    一个提供懒加载ViewModel实例的工具类。

  • ViewModelProvider

    用于获取ViewModel实例,确保配置更改时ViewModel可以持续使用。

  • ViewModelStore

    用于保存ViewModel实例的类,以便它们可以跨配置更改持续存在。

  • ViewModelStoreOwner

    一个接口,标识一个类可以拥有ViewModelStore。

  • ViewTreeViewModelStoreOwner

    用于从视图树中查找ViewModelStoreOwner的工具类。

  • ViewTreeViewModelKt

    提供了操作和查询视图树中ViewModel的Kotlin扩展

页面旋转的时候 ViewModelStore 到底被谁持有了

ViewModelStore

Activity 的销毁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/** 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);
}
}
}
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnDestroy(r.activity);
if (!r.activity.mCalled) {
throw new SuperNotCalledException("Activity " + safeToComponentShortString(r.intent)
+ " did not call through to super.onDestroy()");
}
if (r.window != null) {
r.window.closeAllPanels();
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException("Unable to destroy activity "
+ safeToComponentShortString(r.intent) + ": " + e.toString(), e);
}
}
r.setState(ON_DESTROY);
mLastReportedWindowingMode.remove(r.activity.getActivityToken());
schedulePurgeIdler();
synchronized (this) {
if (mSplashScreenGlobal != null) {
mSplashScreenGlobal.tokenDestroyed(r.token);
}
}
// updatePendingActivityConfiguration() reads from mActivities to update
// ActivityClientRecord which runs in a different thread. Protect modifications to
// mActivities to avoid race.
synchronized (mResourcesManager) {
mActivities.remove(r.token);
}
StrictMode.decrementExpectedActivityCount(activityClass);
}

关键代码

1
2
3
4
5
6
7
8
9
10
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);
}
}
}

android.app.Activity

retainNonConfigurationInstances

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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;
}

onRetainNonConfigurationInstance

1
2
3
public Object onRetainNonConfigurationInstance() {
return null;
}

onRetainNonConfigurationChildInstances

1
2
3
4
@Nullable
HashMap<String,Object> onRetainNonConfigurationChildInstances() {
return null;
}

androidx.activity.ComponentActivity

onRetainNonConfigurationInstance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Retain all appropriate non-config state. You can NOT
* override this yourself! Use a {@link androidx.lifecycle.ViewModel} if you want to
* retain your own non config state.
*/
@Override
@Nullable
@SuppressWarnings("deprecation")
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;
}

关键代码

1
2
3
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;

androidx.activity.ComponentActivity 中实现了 onRetainNonConfigurationInstance

ViewModelStore 被保存到了 NonConfigurationInstances.viewModelStore 中

NonConfigurationInstances 又被 ActivityClientRecord 持有

android.app.ActivityThread.ActivityClientRecord 源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
public static final class ActivityClientRecord {
@UnsupportedAppUsage
public IBinder token;
public IBinder assistToken;
// A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
// used without security checks
public IBinder shareableActivityToken;
// The token of the initial TaskFragment that embedded this activity. Do not rely on it
// after creation because the activity could be reparented.
@Nullable public IBinder mInitialTaskFragmentToken;
int ident;
@UnsupportedAppUsage
Intent intent;
String referrer;
IVoiceInteractor voiceInteractor;
Bundle state;
PersistableBundle persistentState;
@UnsupportedAppUsage
Activity activity;
Window window;
Activity parent;
String embeddedID;
Activity.NonConfigurationInstances lastNonConfigurationInstances;
// TODO(lifecycler): Use mLifecycleState instead.
@UnsupportedAppUsage
boolean paused;
@UnsupportedAppUsage
boolean stopped;
boolean hideForNow;
Configuration createdConfig;
Configuration overrideConfig;
// Used for consolidating configs before sending on to Activity.
private Configuration tmpConfig = new Configuration();
// Callback used for updating activity override config and camera compat control state.
ViewRootImpl.ActivityConfigCallback activityConfigCallback;
ActivityClientRecord nextIdle;

// Indicates whether this activity is currently the topmost resumed one in the system.
// This holds the last reported value from server.
boolean isTopResumedActivity;
// This holds the value last sent to the activity. This is needed, because an update from
// server may come at random time, but we always need to report changes between ON_RESUME
// and ON_PAUSE to the app.
boolean lastReportedTopResumedState;

ProfilerInfo profilerInfo;

@UnsupportedAppUsage
ActivityInfo activityInfo;
@UnsupportedAppUsage
CompatibilityInfo compatInfo;
@UnsupportedAppUsage
public LoadedApk packageInfo;

List<ResultInfo> pendingResults;
List<ReferrerIntent> pendingIntents;

boolean startsNotResumed;
public final boolean isForward;
int pendingConfigChanges;
// Whether we are in the process of performing on user leaving.
boolean mIsUserLeaving;

Window mPendingRemoveWindow;
WindowManager mPendingRemoveWindowManager;
@UnsupportedAppUsage
boolean mPreserveWindow;

/** The options for scene transition. */
ActivityOptions mActivityOptions;

/** Whether this activiy was launched from a bubble. */
boolean mLaunchedFromBubble;

@LifecycleState
private int mLifecycleState = PRE_ON_CREATE;

private SizeConfigurationBuckets mSizeConfigurations;

@VisibleForTesting
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public ActivityClientRecord() {
this.isForward = false;
init();
}

public ActivityClientRecord(IBinder token, Intent intent, int ident,
ActivityInfo info, Configuration overrideConfig, CompatibilityInfo compatInfo,
String referrer, IVoiceInteractor voiceInteractor, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble,
IBinder initialTaskFragmentToken) {
this.token = token;
this.assistToken = assistToken;
this.shareableActivityToken = shareableActivityToken;
this.ident = ident;
this.intent = intent;
this.referrer = referrer;
this.voiceInteractor = voiceInteractor;
this.activityInfo = info;
this.compatInfo = compatInfo;
this.state = state;
this.persistentState = persistentState;
this.pendingResults = pendingResults;
this.pendingIntents = pendingNewIntents;
this.isForward = isForward;
this.profilerInfo = profilerInfo;
this.overrideConfig = overrideConfig;
this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo,
compatInfo);
mActivityOptions = activityOptions;
mLaunchedFromBubble = launchedFromBubble;
mInitialTaskFragmentToken = initialTaskFragmentToken;
init();
}

/** Common initializer for all constructors. */
private void init() {
parent = null;
embeddedID = null;
paused = false;
stopped = false;
hideForNow = false;
nextIdle = null;
activityConfigCallback = new ViewRootImpl.ActivityConfigCallback() {
@Override
public void onConfigurationChanged(Configuration overrideConfig,
int newDisplayId) {
if (activity == null) {
throw new IllegalStateException(
"Received config update for non-existing activity");
}
activity.mMainThread.handleActivityConfigurationChanged(
ActivityClientRecord.this, overrideConfig, newDisplayId);
}

@Override
public void requestCompatCameraControl(boolean showControl,
boolean transformationApplied, ICompatCameraControlCallback callback) {
if (activity == null) {
throw new IllegalStateException(
"Received camera compat control update for non-existing activity");
}
ActivityClient.getInstance().requestCompatCameraControl(
activity.getResources(), token, showControl, transformationApplied,
callback);
}

};
}

/** Get the current lifecycle state. */
public int getLifecycleState() {
return mLifecycleState;
}

/** Update the current lifecycle state for internal bookkeeping. */
public void setState(@LifecycleState int newLifecycleState) {
mLifecycleState = newLifecycleState;
switch (mLifecycleState) {
case ON_CREATE:
paused = true;
stopped = true;
break;
case ON_START:
paused = true;
stopped = false;
break;
case ON_RESUME:
paused = false;
stopped = false;
break;
case ON_PAUSE:
paused = true;
stopped = false;
break;
case ON_STOP:
paused = true;
stopped = true;
break;
}
}

private boolean isPreHoneycomb() {
return activity != null && activity.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.HONEYCOMB;
}

private boolean isPreP() {
return activity != null && activity.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.P;
}

public boolean isPersistable() {
return activityInfo.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS;
}

public boolean isVisibleFromServer() {
return activity != null && activity.mVisibleFromServer;
}

public String toString() {
ComponentName componentName = intent != null ? intent.getComponent() : null;
return "ActivityRecord{"
+ Integer.toHexString(System.identityHashCode(this))
+ " token=" + token + " " + (componentName == null
? "no component name" : componentName.toShortString())
+ "}";
}

public String getStateString() {
StringBuilder sb = new StringBuilder();
sb.append("ActivityClientRecord{");
sb.append("paused=").append(paused);
sb.append(", stopped=").append(stopped);
sb.append(", hideForNow=").append(hideForNow);
sb.append(", startsNotResumed=").append(startsNotResumed);
sb.append(", isForward=").append(isForward);
sb.append(", pendingConfigChanges=").append(pendingConfigChanges);
sb.append(", preserveWindow=").append(mPreserveWindow);
if (activity != null) {
sb.append(", Activity{");
sb.append("resumed=").append(activity.mResumed);
sb.append(", stopped=").append(activity.mStopped);
sb.append(", finished=").append(activity.isFinishing());
sb.append(", destroyed=").append(activity.isDestroyed());
sb.append(", startedActivity=").append(activity.mStartedActivity);
sb.append(", changingConfigurations=").append(activity.mChangingConfigurations);
sb.append("}");
}
sb.append("}");
return sb.toString();
}
}

ActivityClientRecord是Android系统内部使用的一个类,主要存在于ActivityThread中,用于管理和跟踪Activity的状态信息。这个类作为Activity实例状态的容器,承载了Activity的生命周期状态、Intent信息、窗口和其他与Activity实例相关的配置信息。ActivityClientRecordActivityThread处理Activity生命周期事件时的关键数据结构,它帮助ActivityThread高效地管理Activity的创建、启动、恢复、暂停、停止以及销毁过程。

主要职责

  • 生命周期管理ActivityClientRecord存储了Activity的生命周期状态,例如是否处于暂停状态、是否已经创建等,这对于ActivityThread正确处理Activity生命周期事件至关重要。

  • 配置管理:它还包含了与Activity实例相关的配置信息,如屏幕方向、主题等,这些信息对于Activity在不同配置下正确表现自己非常重要。

  • Intent处理ActivityClientRecord包含了启动Activity所用的Intent,这个Intent携带了从其他组件传递给Activity的数据。

  • 窗口管理:它还管理着Activity的窗口信息,包括用于描绘Activity UI的窗口。这对于在屏幕上正确渲染Activity视图非常关键。

工作原理

当一个新的Activity被启动时,ActivityThread会接收到一个来自AMS(Activity Manager Service)的请求,此请求包含了创建或启动Activity所需的所有信息,包括Intent和Activity的配置信息。ActivityThread随后会创建一个新的ActivityClientRecord实例,用来存储这些信息,并根据这些信息处理Activity的创建和启动过程。

在Activity的生命周期中,ActivityThread会根据接收到的来自AMS的指令,更新ActivityClientRecord的状态,并据此调用Activity的相应生命周期方法,如onCreateonStartonResumeonPauseonStoponDestroy

重要性

虽然ActivityClientRecord是一个内部类,不面向普通开发者,但了解它的存在和作用有助于深入理解Android的Activity管理机制。它是ActivityThread和AMS协同工作、高效管理Activity生命周期的关键数据结构,确保了Activity可以在正确的时间执行正确的操作,从而为用户提供流畅的应用体验。

,