内容简介:当设备配置发生变更时,系统会调用AMS的可以看到可以看到,决定返回值的是
当设备配置发生变更时,系统会调用AMS的 updateConfiguration()
方法,来通知AMS处理configuration changed事件, updateConfiguration()
源码如下:
public boolean updateConfiguration(Configuration values) { // ... 省略一段代码 synchronized(this) { // ... 省略一段代码 try { if (values != null) { Settings.System.clearConfiguration(values); } updateConfigurationLocked(values, null, false, false /* persistent */, UserHandle.USER_NULL, false /* deferResume */, mTmpUpdateConfigurationResult); return mTmpUpdateConfigurationResult.changes != 0; } finally { Binder.restoreCallingIdentity(origId); } } } 复制代码
可以看到 updateConfiguration()
内部调用了 private boolean updateConfigurationLocked()
,在其代码注释中我们可以看到,该方法一共做了两件事:
1.调用 updateGlobalConfigurationLocked()
更新当前配置信息
2.调用 ensureConfigAndVisibilityAfterUpdate()
确保给定的activity使用的是当前配置
如果返回true表示activity未被重启,否则让该activity destroyed以适配当前配置。 ensureConfigAndVisibilityAfterUpdate()
的源码如下:
private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) { boolean kept = true; // 获取当前拥有焦点的activity final ActivityStack mainStack = mStackSupervisor.getFocusedStack(); // mainStack is null during startup. if (mainStack != null) { if (changes != 0 && starting == null) { // If the configuration changed, and the caller is not already // in the process of starting an activity, then find the top // activity to check if its configuration needs to change. starting = mainStack.topRunningActivityLocked(); } if (starting != null) { // 关键代码 kept = starting.ensureActivityConfiguration(changes, false /* preserveWindow */); // And we need to make sure at this point that all other activities // are made visible with the correct configuration. mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes, !PRESERVE_WINDOWS); } } return kept; } 复制代码
可以看到,决定返回值的是 ActivityRecord
的 ensureActivityConfiguration()
方法,并在内部调用了该方法的重载方法,其源码如下:
boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow, boolean ignoreStopState) { final ActivityStack stack = getStack(); // 如果马上就会再次调用updateConfiguration(),则忽略本次修改,交由下次处理,节省时间 if (stack.mConfigWillChange) { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Skipping config check (will change): " + this); return true; } // We don't worry about activities that are finishing. // 如果当前activity已经finish则忽略 if (finishing) { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Configuration doesn't matter in finishing " + this); stopFreezingScreenLocked(false); return true; } // ...省略一段代码 if (mState == INITIALIZING) { // No need to relaunch or schedule new config for activity that hasn't been launched // yet. We do, however, return after applying the config to activity record, so that // it will use it for launch transaction. if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Skipping config check for initializing activity: " + this); return true; } if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) { // Aha, the activity isn't handling the change, so DIE DIE DIE. configChangeFlags |= changes; startFreezingScreenLocked(app, globalChanges); forceNewConfig = false; preserveWindow &= isResizeOnlyChange(changes); if (app == null || app.thread == null) { // ...省略log代码 // 如果app不在托管状态,则仅销毁当前activity stack.destroyActivityLocked(this, true, "config"); } else if (mState == PAUSING) { // ...省略log代码 // 如果当前activity处于PAUSING状态,则标记其需要重启,等到PAUSING后reLaunch deferRelaunchUntilPaused = true; preserveWindowOnDeferredRelaunch = preserveWindow; return true; } else if (mState == RESUMED) { // ...省略一段代码 // 如果当前activity处于RESUMED状态,则重启后需要恢复到RESUMED状态 relaunchActivityLocked(true /* andResume */, preserveWindow); } else { // ...省略log代码 relaunchActivityLocked(false /* andResume */, preserveWindow); } // activity自行处理了configuration changed,无需重启 return false; } // Activity可以自己处理配置变更则走这里 if (displayChanged) { scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); } else { scheduleConfigurationChanged(newMergedOverrideConfig); } return true; } 复制代码
可以看到决定是否重启的关键代码是 shouldRelaunchLocked(changes, mTmpConfig)
。另外一个值得关注的点是 forceNewConfig
变量,其值仅在 ActivityStack.restartPackage()
时为 true
,此时会忽略activity的 configChanges
配置,强制重启activity。 shouldRelaunchLocked
的源码如下:
private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) { // 获取manifest中配置的configChanges属性 int configChanged = info.getRealConfigChanged(); boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig); // Override for apps targeting pre-O sdks // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode // to the config change. // For O and later, apps will be required to add configChanges="uimode" to their manifest. if (appInfo.targetSdkVersion < O && requestedVrComponent != null && onlyVrUiModeChanged) { configChanged |= CONFIG_UI_MODE; } // 关键代码 return (changes&(~configChanged)) != 0; } 复制代码
(changes&(~configChanged)) != 0
决定了是否ReLaunch当前activity,如果变更的配置在activity自处理的配置列表中,则不会重启。而configChanged正是我们在manifest中配置的configChanges属性。
void relaunchActivityLocked(boolean andResume, boolean preserveWindow) { // ...省略一段代码 try { // ...省略log代码 // 关键代码1 final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults, pendingNewIntents, configChangeFlags, new MergedConfiguration(service.getGlobalConfiguration(), getMergedOverrideConfiguration()), preserveWindow); final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem = ResumeActivityItem.obtain(service.isNextTransitionForward()); } else { lifecycleItem = PauseActivityItem.obtain(); } final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken); transaction.addCallback(callbackItem); transaction.setLifecycleStateRequest(lifecycleItem); // 关键代码2 service.getLifecycleManager().scheduleTransaction(transaction); } catch (RemoteException e) { if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e); } // ...省略一段代码 } 复制代码
首先我们看关键代码1: ActivityRelaunchItem.obtain()
。 ActivityRelaunchItem
继承自``,其中在 execute()
中调用了 client.handleRelaunchActivity(mActivityClientRecord, pendingActions)
。
最终 ClientTransaction
的callback的 execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions)
都会被调用,而添加的callback: ActivityRelaunchItem
的 execute
如下:
public void execute(ClientTransactionHandler client, IBinder token,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); } 复制代码
ClientTransactionHandler
是一个抽象类,这里实际是通过 ClientTransaction.obtain(app.thread, appToken)
传入的 IApplicationThread
对象,app.thread是在 attachApplication()
方法中设置的,其实现类是 ApplicationThread
,而其内部调用的是 ActivityThread.handleRelaunchActivity()
,该方法在其父类中实现:
void scheduleTransaction(ClientTransaction transaction) { transaction.preExecute(this); sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); } 复制代码
其中 sendMessage()
由 ActivityThread
实现,最终交由H处理:
case EXECUTE_TRANSACTION: final ClientTransaction transaction = (ClientTransaction) msg.obj; mTransactionExecutor.execute(transaction); if (isSystem()) { transaction.recycle(); } break; 复制代码
mTransactionExecutor
是 TransactionExecutor
的实例,其 execute()
方法最终会调用 executeCallbacks(transaction)
调用通过 ClientTransaction#addCallback()
方法添加的所有 ClientTransactionItem
实例的 execute()
。最终会调用 ActivityThread.handleRelaunchActivity()
:
public void handleRelaunchActivity(ActivityClientRecord tmp,PendingTransactionActions pendingActions) { // ...省略一段代码 if (changedConfig != null) { mCurDefaultDisplayDpi = changedConfig.densityDpi; updateDefaultDensity(); handleConfigurationChanged(changedConfig, null); } ActivityClientRecord r = mActivities.get(tmp.token); // ...省略一段代码 handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents, pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity"); // ...省略一段代码 } 复制代码
在 handleRelaunchActivityInner()
中,先调用 ActivityThread.handleDestroyActivity()
销毁当前activity,随便调用 ActivityThread.handleLaunchActivity()
重启了activity。我们都知道,Activity有一个回调方法 onRetainNonConfigurationInstance()
,当设备信息变更时,会保存该方法返回的Object,之后可以在重启的Activity中通过 getLastNonConfigurationInstance()
获取该Object。 onRetainNonConfigurationInstance()
并非仅会在发生reLaunchActivity时回调,而是在Activity destoryed时,在 ActivityThread.performDestroyActivity()
中调用 Activity.retainNonConfigurationInstances()
获取的。该方法返回的是 NonConfigurationInstances
,其 activity
属性便是调用 Activity.onRetainNonConfigurationInstance()
获取的。而之所以 getLastNonConfigurationInstance()
能获取到值,是因为在reLaunchActivity中将同一 ActivityRecord
作为参数,传递给了新Activity。该方法是在 ComponentActivity
,已经被重写为final方法,子类如果想保存数据,可以通过 onRetainCustomNonConfigurationInstance
替代,但是官方推荐使用ViewModel组件来替代它,而ViewModel之所以会在设备旋转后恢复,便是通过这种方式保存的。
现在要解决的疑惑是,当变更的配置在activity自处理的配置列表时,activity仅会回调 onConfigurationChanged(Configuration)
,这又是在哪里调用的呢?答案就在 ActivityRecord
的 ensureActivityConfiguration()
方法中。
// Activity可以自己处理配置变更则走这里 if (displayChanged) { scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); } else { scheduleConfigurationChanged(newMergedOverrideConfig); } 复制代码
这两个分支,最终都会调用 ClientTransactionHandler.handleActivityConfigurationChanged()
方法,该方法由 ActivityThread
实现:
public void handleActivityConfigurationChanged(IBinder activityToken,Configuration overrideConfig, int displayId) { // ...省略一段代码 final boolean movedToDifferentDisplay = displayId != INVALID_DISPLAY && displayId != r.activity.getDisplay().getDisplayId(); // ...省略一段代码 if (movedToDifferentDisplay) { // ...省略一段代码 final Configuration reportedConfig = performConfigurationChangedForActivity(r, mCompatConfiguration, displayId, true /* movedToDifferentDisplay */); // ...省略一段代码 } else { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: " + r.activityInfo.name + ", config=" + overrideConfig); performConfigurationChangedForActivity(r, mCompatConfiguration); } // ...省略一段代码 } 复制代码
performConfigurationChangedForActivity()
最终会调用 performActivityConfigurationChanged()
方法,该方法如下:
private Configuration performActivityConfigurationChanged(Activity activity,Configuration newConfig, Configuration amOverrideConfig, int displayId,boolean movedToDifferentDisplay) { // ...省略一段代码 boolean shouldChangeConfig = false; if (activity.mCurrentConfig == null) { shouldChangeConfig = true; } else { // If the new config is the same as the config this Activity is already running with and // the override config also didn't change, then don't bother calling // onConfigurationChanged. final int diff = activity.mCurrentConfig.diffPublicOnly(newConfig); if (diff != 0 || !mResourcesManager.isSameResourcesOverrideConfig(activityToken, amOverrideConfig)) { // Always send the task-level config changes. For system-level configuration, if // this activity doesn't handle any of the config changes, then don't bother // calling onConfigurationChanged as we're going to destroy it. // 如果共用配置发生变更 // mUpdatingSystemConfig这里为false所以shouldChangeConfig=true if (!mUpdatingSystemConfig || (~activity.mActivityInfo.getRealConfigChanged() & diff) == 0 || !REPORT_TO_ACTIVITY) { shouldChangeConfig = true; } } } if (!shouldChangeConfig && !movedToDifferentDisplay) { // Nothing significant, don't proceed with updating and reporting. return null; } // ...省略一段代码 if (shouldChangeConfig) { activity.mCalled = false; activity.onConfigurationChanged(configToReport); if (!activity.mCalled) { throw new SuperNotCalledException("Activity " + activity.getLocalClassName() + " did not call through to super.onConfigurationChanged()"); } } return configToReport; } 复制代码
最终我们找到了 activity.onConfigurationChanged(configToReport)
调用位置。至此,设备变更是,activity的生命周期调用流程分析完毕。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- PyMiner 开源协议变更为 LGPL,技术变更为 PySide2
- 使用JGit获取变更细节
- 每日获取变更的CVE漏洞
- Raft 成员变更的工程实践
- 生产变更的几点感悟
- 需求变更控制有哪些先进技术?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Landing Page Optimization
Tim Ash / Wiley Publishing / 2008-1-29 / USD 29.99
在线阅读本书 How much money are you losing because of poor landing page design? In this comprehensive, step-by-step guide, you’ll learn all the skills necessary to dramatically improve your bottom li......一起来看看 《Landing Page Optimization》 这本书的介绍吧!