目录
- Activity创立ViewModel
-
Activity重建ViewModel坚持存在的完成
- relaunch之后新的Activity获取之前的viewModel
- relaunch过程中保存旧Activity的viewModel
- reference
2022/08/21
Activity创立ViewModel
-
创立ViewModel
// MyActivity#onCreate() val mainViewModel = [V1] ViewModelProvider(this) [V2] .get(MainViewModel::class.java)
-
[V1]
ViewModelProvider结构函数
// androidx.lifecycle.ViewModelProvider#get(java.lang.Class<T>) public constructor( owner: ViewModelStoreOwner ) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
this指MyActivity,即MyActivity应该是
[I]ViewModelStoreOwner
类型MyActivity承继
[C]ComponentActivity]
,ComponentActivity完成了[I]ViewModelStoreOwner
接口// CompnentActivity public class ComponentActivity extends androidx.core.app.ComponentActivity implements // ... ViewModelStoreOwner, // ... {
this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
,这儿运用owner.viewModelStore
从ViewModelStoreOwner中取出[OC]ViewModelStore]
// ViewModelStoreOwner interface ViewModelStoreOwner { /** * The owned [ViewModelStore] */ val viewModelStore: ViewModelStore }
然后调用下面的结构函数
// ViewModelStoreOwner /** * Creates a ViewModelProvider * * @param store `ViewModelStore` where ViewModels will be stored. * @param factory factory a `Factory` which will be used to instantiate new `ViewModels` * @param defaultCreationExtras extras to pass to a factory */ @JvmOverloads constructor( private val store: ViewModelStore, private val factory: Factory, private val defaultCreationExtras: CreationExtras = CreationExtras.Empty, ) {
-
[V2]
调用了get办法⬇️
// androidx.lifecycle.ViewModelProvider#get(java.lang.Class<T>) @MainThread public open operator fun <T : ViewModel> get(modelClass: Class<T>): T { val canonicalName = modelClass.canonicalName ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels") [W1] return get("$DEFAULT_KEY:$canonicalName", modelClass) }
-
[W1]
// androidx.lifecycle.ViewModelProvider#get(java.lang.String, java.lang.Class<T>) @MainThread public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T { [X1]val viewModel = store[key] [X1]if (modelClass.isInstance(viewModel)) { .... [X1] return viewModel as T .... [X2]return try { [X2] factory.create(modelClass, extras) [X2] catch (e: AbstractMethodError) { [X2] factory.create(modelClass) [X2]}.also { store.put(key, it) } }
-
[X1]
⬅️[W1]
从store(
[OC]ViewModelStore
)中能找到viewmodel则直接回来 -
[X2]
⬅️[W1]
store中找不到则需要新创立一个viewmodel并放入store,这儿说明只需运用同一个ViewModelStore获取ViewModel则不同当地获取到的都是同一个ViewModel
[OC]ViewModelStore
看起来是个Map,事实上他的完成便是保护一个map,放出get和put办法open class ViewModelStore { private val map = mutableMapOf<String, ViewModel>() ... fun put(key: String, viewModel: ViewModel) { } operator fun get(key: String): ViewModel? { return map[key] } ... }
总结上面,Activity在onCreate时创立viewModel,Activity是一个ViewModelStoreOwner其间有一个ViewModelStore其间保护一个map,ViewModelProvier作为一个工具类在运用默许的/我们供给的Factory(为了适配结构函数有参的ViewModel)创立ViewModel的一起会将其存入这个map。
所以,在relaunch过程中,毁掉旧的Activity时假如能保存它的mViewModelStore,然后将其赋值新的Activity的mViewModelStore就能完成装备改变viewModel不改变的效果。
Activity重建ViewModel坚持存在的完成
relaunch之后新的Activity获取之前的viewModel
viewModel存在ViewModelStore中,说明ViewModelStore在Activity重建的过程中能坚持存在,看下[C]ComponentActivity
怎么怎么获取[OC]ViewModelStore
的
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.");
}
[T1] ensureViewModelStore();
return mViewModelStore;
}
-
[T1]
在getViewModelStore()办法中调用了ensureViewModelStore()保证mViewModelStore不为空
@SuppressWarnings("WeakerAccess") /* synthetic access */ void ensureViewModelStore() { if (mViewModelStore == null) { [U1] NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null) { // Restore the ViewModelStore from NonConfigurationInstances [U2] mViewModelStore = nc.viewModelStore; } if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } } }
-
[U1]
⬅️[T1]
// Activity @Nullable public Object getLastNonConfigurationInstance() { return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null; }
Activirty.mLastNonConfigurationInstances类型为
[C]Activity.NonConfigurationInstances
// android.app.Activity.NonConfigurationInstances static final class NonConfigurationInstances { Object activity; .... }
mLastNonConfigurationInstances.activity在
[U1]
⬅️[T1]
处被强转为[C]ComponentActivity.NonConfigurationInstances
// androidx.activity.ComponentActivity.NonConfigurationInstances static final class NonConfigurationInstances { Object custom; ViewModelStore viewModelStore; }
-
[U2]
⬅️[T1]
假如
[U1]
获取的nc不为空,则将mViewModelStore赋值为nc.viewModelStore 即Activity.mLastNonConfigurationInstances.activity.viewModelStore所以想要保存给新Activity运用本来的viewModel,重点便是要在relaunch过程中保存旧的Activity.mLastNonConfigurationInstances然后再赋值给新Activity.mLastNonConfigurationInstances
relaunch过程中保存旧Activity的viewModel
设备改变,系统调用AMS的updateConfiguration 办法
ActivityManagerService.java – Android Code Search
// ActivityManagerService
@Override
public boolean updateConfiguration(Configuration values) {
return mActivityTaskManager.updateConfiguration(values);
}
// ActivityTaskManagerService
@Override
public boolean updateConfiguration(Configuration values) {
....
updateConfigurationLocked(values, null, false, false /* persistent */,
....
}
// ActivityTaskManagerService
boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
boolean initLocale, boolean persistent, int userId, boolean deferResume,
ActivityTaskManagerService.UpdateConfigurationResult result) {
....
「I1」 changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId);
....
「I2」 kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
....
}
-
「I1」
updateGlobalConfigurationLocked 更新当时装备信息
-
「I2」
ensureConfigAndVisibilityAfterUpdate 保证给定的activity更新运用的装备
这儿starting传入的是null,需要ensureConfigAndVisibilityAfterUpdate中自己获取
// ActivityTaskManagerService boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { boolean kept = true; 「J1」 final Task mainRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); .... 「J2」 starting = mainRootTask.topRunningActivity(); .... 「J3」 kept = starting.ensureActivityConfiguration(changes, .... }
-
「J1」
⬅️「I2」
获取根窗口容器中当时具有焦点的尖端任务(root task)
-
「J2」
⬅️「I2」
获取尖端任务(root task)中当时正在运转的尖端Activity(top running Activity)的ActivityRecord赋值给starting
-
「J3」
⬅️「I2」
ActivityRecord对应的Activity更新Configuration
// com.android.server.wm.ActivityRecord#ensureActivityConfiguration(int, boolean) boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) { return ensureActivityConfiguration(globalChanges, preserveWindow, false /* ignoreVisibility */); }
// com.android.server.wm.ActivityRecord#ensureActivityConfiguration(int, boolean, boolean) boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow, boolean ignoreVisibility) { .... relaunchActivityLocked(preserveWindow); .... }
// com.android.server.wm.ActivityRecord#relaunchActivityLocked void relaunchActivityLocked(boolean preserveWindow) { .... 「K2」 final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults, .... 「K1」 final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), token); 「K2」 transaction.addCallback(callbackItem); .... 「K3」 mAtmService.getLifecycleManager().scheduleTransaction(transaction); .... }
-
「K1」
⬅️「J3」
token来自
[C]ActivityRecord
承继的[C]WindowToken
中的tokenclass WindowToken extends WindowContainer<WindowState> { private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowToken" : TAG_WM; /** The actual token */ final IBinder token; /** The type of window this token is for, as per {@link WindowManager.LayoutParams} */ final int windowType;
// ClientTransaction /** Obtain an instance initialized with provided params. */ public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) { ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class); if (instance == null) { instance = new ClientTransaction(); } instance.mClient = client; instance.mActivityToken = activityToken; return instance; }
将transaction.mActivityToken设置为ActivityRecord.token
-
「K2」
⬅️「J3」
给transaction放入callback:
[C]ActivityRelaunchItem
-
「K3」
⬅️「J3」
履行transaction
// com.android.server.wm.ClientLifecycleManager#scheduleTransaction(ClientTransaction) void scheduleTransaction(ClientTransaction transaction) throws RemoteException { .... transaction.schedule(); .... }
// ClientTransaction public void schedule() throws RemoteException { 「L1」 mClient.scheduleTransaction(this); }
-
「L1」
⬅️「K3」
[C]ClientTransaction
运用mClient履行自己- mClient是什么?
// ClientTransaction /** Target client. */ private IApplicationThread mClient;
这儿是运用AIDL(根据Binder)进行进程间通信,对应文件
IApplicationThread.aidl
⬇️oneway interface IApplicationThread { .... void scheduleTransaction(in ClientTransaction transaction);
这儿mClient是客户端,对应的客户端为
[c]ApplicationThread
private class ApplicationThread extends IApplicationThread.Stub {
- mClient是什么?
-
「M1」
⬅️「L1」
所以下面从 android.app.ActivityThread.ApplicationThread#scheduleTransaction办法继续
// android.app.ActivityThread.ApplicationThread#scheduleTransaction @Override public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { ActivityThread.this.scheduleTransaction(transaction); }
这儿scheduleTransaction是调用的ActivityThread的基类ClientTransactonHandler中的scheduleTransaction办法
// android.app.ClientTransactionHandler#scheduleTransaction void scheduleTransaction(ClientTransaction transaction) { 「N1」 transaction.preExecute(this); 「N2」 sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); }
-
「N1」
⬅️「M1」
为后面transaction的履行做些预备,这儿this传入的是
[C]ActivityThread
public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) { if (mActivityCallbacks != null) { .... for (int i = 0; i < size; ++i) { 「O1」 mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken); .... }
-
「O1」
⬅️「N1」
履行每个callback的preExecute办法,callback只有一个之前在
「K2」
处放入的ActivityRelaunchItem// android.app.servertransaction.ActivityRelaunchItem#preExecute public void preExecute(ClientTransactionHandler client, IBinder token) { 「P1」 mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults, mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow); }
-
「P1」
⬅️「O1」
从ActivityThread(即client)获取要relaunch的ActivityRecord存入ActivityRelaunchItem.mActivityClientRecord
@Override public ActivityClientRecord prepareRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config, boolean preserveWindow) { 「Q1」 .... 「Q2」 target = new ActivityClientRecord(); 「Q2」 target.token = token; .... 「Q3」 mRelaunchingActivities.add(target); .... return ....target....; }
-
「Q1」
⬅️「P1」
检查是否方针activity是否现已正在relaunch了,假如是则回来
-
「Q2」
⬅️「P1」
方针activity没有现已正在relaunch(这儿认为是没有,这个判别只是为了避免relaunch正在relaunch的activity),则结构一个
[sC]ActivityClientRecord
记录要relaunch的Activity的token等信息 -
「Q3」
⬅️「P1」
运用ActivityThread.mRelaunchingActivities记录一切要预备重启的ActivityClientRecord+-----------------------------------------------------+ | | | ActivityThread | | | | +-----------------------------------+ | | | mRelaunchingActivities | | | | | | | | +------------------------+ | | | | | ActivityClientRecord | | | | | +------------------------+ | | | | | | | | +------------------------+ | | | | | ActivityClientRecord | | | | | +------------------------+ | | | | | | | | .... | | | | | | | | | | | +-----------------------------------+ | | | +-----------------------------------------------------+
-
「N2」
⬅️「M1」
这儿运用Handler去真实履行transaction,obj传入的便是transaction
// android.app.ClientTransactionHandler#sendMessage abstract void sendMessage(int what, Object obj);
// android.app.ActivityThread#sendMessage(int, java.lang.Object) void sendMessage(int what, Object obj) { sendMessage(what, obj, 0, 0, false); }
⬇️结构Message
// android.app.ActivityThread#sendMessage(int, java.lang.Object, int, int, boolean) private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { .... msg.what = what; msg.obj = obj; .... mH.sendMessage(msg); }
⬇️handler:ActivityThread.H 收到音讯并处理
// android.app.ActivityThread.H#handleMessage public void handleMessage(Message msg) { ... switch (msg.what) { ... case EXECUTE_TRANSACTION: 「R1」 final ClientTransaction transaction = (ClientTransaction) msg.obj; 「R2」 mTransactionExecutor.execute(transaction); ....
-
「R1」
⬅️「N2」
从message中取出transaction -
「R2」
⬅️「N2」
交给mTransactionExecutor履行mTransactionHandler 是谁?是
[C]ActivityThread
,从TransactionExecutor的结构函数⬇️中能够看出// ActivityThread private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);
/** Initialize an instance with transaction handler, that will execute all requested actions. */ public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) { mTransactionHandler = clientTransactionHandler; }
TransactionExecutor.mTransactionHandler是对持有该TransactionExecutor的ActivityThread的引证
+-------------------------------------------------------------------------------------+ | ActivityThread <-------+ | | | | | | | | +-----------------------------------------------------------------+ | | | mTransactionExecutor: TransactionExecutor | | | | | | | | | | | | | | | +-------------------------------------------------+---------+ | | | | | mTransactionHandler: ClientTransactionHandler | | | | | | | | | | | | | | | | | +-----------------------------------------------------------+ | | | | | | | | | | | +-----------------------------------------------------------------+ | | | +-------------------------------------------------------------------------------------+
// android.app.servertransaction.TransactionExecutor#execute public void execute(ClientTransaction transaction) { .... executeCallbacks(transaction); .... }
// android.app.servertransaction.TransactionExecutor#executeCallbacks public void executeCallbacks(ClientTransaction transaction) { final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); .... 「S1」 final IBinder token = transaction.getActivityToken(); .... for (int i = 0; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); .... 「S2」 item.execute(mTransactionHandler, token, mPendingActions); .... }
-
「S1」
⬅️「R2」
从transaction中获取activityToken
「K1」
⬅️「J3」
-
「S2」
⬅️「R2」
callback(为ActivityRelaunchItem)履行,execute办法来自ActivityRelaunchItem 完成的接口BaseClientRequest的execute办法
至于mTransactionHandler是谁,在
「R2」
现已解释execute办法来自ActivityRelaunchItem完成的接口BaseClientRequest中的execute办法⬇️
public interface BaseClientRequest extends ObjectPoolItem { .... void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions); .... }
ActivityRelaunchItem和BaseClientRequest的关系⬇️
public abstract class ClientTransactionItem implements BaseClientRequest
public abstract class ActivityTransactionItem extends ClientTransactionItem
public class ActivityRelaunchItem extends ActivityTransactionItem
classDiagram class ClientTransactionItem { } class ActivityTransactionItem { } class ActivityRelaunchItem { } class BaseClientRequest { <<interface>> + execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) } ClientTransactionItem <|-- ActivityTransactionItem ActivityTransactionItem <|-- ActivityRelaunchItem BaseClientRequest <|-- ClientTransactionItem: implements
该execute办法由
[C]ActivityRelaunchItem
的基类ActivityTransactionItem完成// ActivityTransactionItem public final void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { 「A1」 final ActivityClientRecord r = getActivityClientRecord(client, token); 「A2」 execute(client, r, pendingActions); }
-
「A1」
根据token获取ActivityClientRecord// ActivityTransactionItem @NonNull ActivityClientRecord getActivityClientRecord( @NonNull ClientTransactionHandler client, IBinder token) { final ActivityClientRecord r = client.getActivityClient(token); .... return r; }
client是 TransactionExecutor.mTransactionHandler,也便是持有TransactionExecutor的ActivityThread
// ActivityThread @Override public ActivityClientRecord getActivityClient(IBinder token) { return mActivities.get(token); }
-
「A2」
继续履行 ⬇️// ActivityRelaunchItem @Override public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { .... 「B1」 client.handleRelaunchActivity(mActivityClientRecord, pendingActions); }
-
「B1」
mActivityClientRecord从哪里来?之前「P1」
⬅️「O1」
// ActivityThread @Override public void handleRelaunchActivity(ActivityClientRecord tmp, PendingTransactionActions pendingActions) { ... 「C1」 ActivityClientRecord r = mActivities.get(tmp.token); ... 「C2」handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents, pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity"); ... }
-
「C1」
⬅️「B1」
这儿从
mActivities
中根据token获取[sC]ActivityClientRecord
+----------------------------------------------------------------+ | ActivityThread | | | | | | +------------------------------------------------------+ | | | mActivities | | | | +--------------------------------------+ | | | | | +---------------+ | | | | | | | Activity | | | | | | | +---------------+ | | | | | | | | | | | | +-------------------------------+ | | | | | | | lastNonConfigurationInstances | | | | | | | +-------------------------------+ | | | | | | | | | | | +--------------------------------------+ | | | | +--------------------------------------+ | | | | | | | | | | | | | | | | +--------------------------------------+ | | | | +--------------------------------------+ | | | | | | | | | | | | | | | | +--------------------------------------+ | | | | | | | | ... | | | | | | | +------------------------------------------------------+ | +----------------------------------------------------------------+
-
「C2」
⬅️「B1」
传递r给
// ActivityThread private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents, PendingTransactionActions pendingActions, boolean startsNotResumed, Configuration overrideConfig, String reason) { ... 「D1」 handleDestroyActivity(r, false, configChanges, true, reason); ... 「D2」 handleLaunchActivity(r, pendingActions, customIntent); }
-
「D1」
⬅️「C2」
⬇️Destroy本来的Activity,其间getNonConfigInstance传入了true
// ActivityThread @Override public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) { performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason); ... }
⬇️将本来的activity的nonConfigurationInstances存入ActivityRecord.lastNonConfigurationInstances
// ActivityThread /** Core implementation of activity destroy call. */ void performDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) { ... 「E1」 if (getNonConfigInstance) { .... 「E2」 r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances(); ....
-
「E1」
这儿假如是getNonConfigInstance为true(前面传的是true), -
「E2」
则️将
[sC]ActivityClientRecord
中放入Java 代码块的成果,其间就包括viewModelStore// Activity NonConfigurationInstances retainNonConfigurationInstances() { 「F1」 Object activity = onRetainNonConfigurationInstance(); ... NonConfigurationInstances nci = new NonConfigurationInstances(); nci.activity = activity; .... return nci; }
-
「F1」
Activity默许完成中只回来了null,可是[C]ComponentActivity
重写了这个办法⬇️// ComponentActivity public final Object onRetainNonConfigurationInstance() { // Maintain backward compatibility. 「G1」 Object custom = onRetainCustomNonConfigurationInstance(); ViewModelStore viewModelStore = mViewModelStore; 「G2」 if (viewModelStore == null) { .... } .... 「G3」 NonConfigurationInstances nci = new NonConfigurationInstances(); nci.custom = custom; nci.viewModelStore = viewModelStore; return nci; }
-
「G1」
我们能够经过重写onRetainCustomNonConfigurationInstance()创立custom即自定义的在configuration改变后仍然想要保存的数据。 -
「G2」
这儿当viewModelStore为空的时分会检查[C]ComponentActivity.NonConfigurationInstances
中是否有viewModelStore,这儿对应从来没有当地调用过getViewModelStore,也就不会初始化ComponentActivity.mVieModelStore,可是我们这儿状况是之前有创立viewmodel,this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
,这儿运用owner.viewModelStore
从ViewModelStoreOwner中取出[OC]ViewModelStore
调用过,一切不会走到viewModelStore == null的分支 -
「G3」
这儿创立了[C]ComponentActivity.NonConfigurationInstances
存入 custom和viewModelStore并回来。 -
「D2」
⬅️「C2」
履行LaunchActivity// android.app.ActivityThread#handleLaunchActivity public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { .... final Activity a = performLaunchActivity(r, customIntent); .... return a; }
// android.app.ActivityThread#performLaunchActivity private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { .... Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); 「H1」 activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); .... try { .... if (activity != null) { .... 「H2」 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.activityConfigCallback, r.assistToken, r.shareableActivityToken); .... return activity; }
-
「H1」
实例化一个Activity
-
「H2」
运用本来的ActivityRecord给Activity设置参数,其间第12个参数便是在
「E2」
处保存的lastNonConfigurationInstances,其间就有viewModel这儿就回答了上面
[U2]
处的问题,串起来了
reference
code
- Android 面试总结 – ViewModel 是怎么保存和康复? – ()
- Android Framework之Activity启动流程(一) | 柚子 | pomeloJiang
- Zygote的启动流程 – ()
- Android屏幕旋转源码探索及使用实践 | 奔哲明的博客 (benzblog.site)
- Configuration 改变时Activity的生命周期探求 – ()