当configuration发生变化后,Activity方法onConfigurationChange会被调用,在此具体记录configuration更新在Framework中的调用过程,直至传入Activity;
configuration包含一个应用对手机配置的感知,比如窗口大小、重力方向、手机模式等,可以查看具体成员,
ok,包含配置文件的容器是ConfigurationContainer类,主要成员如下:
/**
* Contains requested override configuration settings applied to this configuration container.
*/
private Configuration mRequestedOverrideConfiguration = new Configuration();
/**
* Contains the requested override configuration with parent and policy constraints applied.
* This is the set of overrides that gets applied to the full and merged configurations.
*/
private Configuration mResolvedOverrideConfiguration = new Configuration();
/** True if mRequestedOverrideConfiguration is not empty */
private boolean mHasOverrideConfiguration;
/**
* Contains full configuration applied to this configuration container. Corresponds to full
* parent's config with applied {@link #mResolvedOverrideConfiguration}.
*/
private Configuration mFullConfiguration = new Configuration();
/**
* Contains merged override configuration settings from the top of the hierarchy down to this
* particular instance. It is different from {@link #mFullConfiguration} because it starts from
* topmost container's override config instead of global config.
*/
private Configuration mMergedOverrideConfiguration = new Configuration();
mRequestedOverrideConfiguration是原始request,container简单将新配置用它保存;mResolvedOverrideConfiguration是特殊处理后的configuration,子类可以通过重写resolveOverrideConfiguration方法修改其中的配置,达到特殊化,父类只是简单将原始request保存到它,并未改写;
mFullConfiguration是实际更新后configuration的最终状态;
mMergedOverrideConfiguration是具备继承效应的configuration,即container改变configuration后,子类将继承此改变,以此类推;
具体,咱们看ConfigurationContainer.onConfiguration方法,
public void onConfigurationChanged(Configuration newParentConfig) {
//临时configuration变量,保存更新之前的mResolvedOverrideConfiguration
mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
//更新mResolvedOverrideConfiguration,可重写此方法增添特殊配置
resolveOverrideConfiguration(newParentConfig);
mFullConfiguration.setTo(newParentConfig);
//根据差异更新最终状态:mFullConfiguration
mFullConfiguration.updateFrom(mResolvedOverrideConfiguration);
//合并此次修改,保存至mMergedOverrideConfiguration
onMergedOverrideConfigurationChanged();
if (!mResolvedTmpConfig.equals(mResolvedOverrideConfiguration)) {
//进入此分支,代表特殊配置修改,通知监听者,
// This depends on the assumption that change-listeners don't do
// their own override resolution. This way, dependent hierarchies
// can stay properly synced-up with a primary hierarchy's constraints.
// Since the hierarchies will be merged, this whole thing will go away
// before the assumption will be broken.
// Inform listeners of the change.
for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
mChangeListeners.get(i).onRequestedOverrideConfigurationChanged(
mResolvedOverrideConfiguration);
}
}
for (int i = mChangeListeners.size() - 1; i >= 0; --i) {
//通知监听者,已经合并父配置修改
mChangeListeners.get(i).onMergedOverrideConfigurationChanged(
mMergedOverrideConfiguration);
}
for (int i = getChildCount() - 1; i >= 0; --i) {
//传达configuration最终状态到子类
final ConfigurationContainer child = getChildAt(i);
child.onConfigurationChanged(mFullConfiguration);
}
}
查看onRequestedOverrideConfigurationChanged方法,当有配置request到达,调用onConfigurationChanged完成上一步;
public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
// Pre-compute this here, so we don't need to go through the entire Configuration when
// writing to proto (which has significant cost if we write a lot of empty configurations).
mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);
mRequestedOverrideConfiguration.setTo(overrideConfiguration);
// Update full configuration of this container and all its children.
final ConfigurationContainer parent = getParent();
onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
}
进入下一步,Activity如何感知到配置的改变?这是一个binder过程,先从Activity生命周期说起;
配置改变后通过binder调用IApplicationThread.scheduleTransaction方法,
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
然后配置改变消息会进入应用进程,经过ActivityThread.H发送消息,执行Transaction,进入TransactionExecutor.executeCallbacks方法,
这个ClientTransactionItem.execute方法如下,
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
// TODO(lifecycler): detect if PIP or multi-window mode changed and report it here.
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
client.handleActivityConfigurationChanged(token, mConfiguration, INVALID_DISPLAY);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
最终调用到performActivityConfigurationChanged方法,执行如下分支,回调Activity.onConfiguration方法,完成应用进程回调;
if (shouldReportChange) {
activity.mCalled = false;
activity.onConfigurationChanged(configToReport);
if (!activity.mCalled) {
throw new SuperNotCalledException("Activity " + activity.getLocalClassName() +
" did not call through to super.onConfigurationChanged()");
}
}
那么系统进程如何传送配置信息到应用进程?这个还得从配置改变说起;
ConfigurationContainer是一个抽象类,直接子类是WindowContainer
WindowContainer是应用Window容器,所有顶层WindowContainer的容器是RootWindowContainer类,当configuration更新后,wms会调用setDisplayOverrideConfigurationIfNeed方法,然后通过ConfigurationContainer前文介绍的方法依次通知children配置update信息;
void setNewDisplayOverrideConfiguration(Configuration overrideConfig,
@NonNull DisplayContent dc) {
if (dc.mWaitingForConfig) {
dc.mWaitingForConfig = false;
mLastFinishedFreezeSource = "new-config";
}
mRoot.setDisplayOverrideConfigurationIfNeeded(overrideConfig, dc);
}
于是乎,通过children调用至ActivityStack.onConfiguration,它继承WindowContainer,
该方法末尾,调用resize方法,再调用ensureVisibleActivitiesConfiguration方法;
void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) {
mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
}
process方法内,会更新配置,然后更新焦距中的Activity
final PooledFunction f = PooledLambda.obtainFunction(
EnsureVisibleActivitiesConfigHelper::processActivity, this,
PooledLambda.__(ActivityRecord.class));
forAllActivities(f, start, true /*includeBoundary*/, true /*traverseTopToBottom*/);
f.recycle();
if (mUpdateConfig) {
// Ensure the resumed state of the focus activity if we updated the configuration of
// any activity.
mRootWindowContainer.resumeFocusedStacksTopActivities();
}
进一步查看processActivity方法,
boolean processActivity(ActivityRecord r) {
mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow);
mBehindFullscreen |= r.occludesParent();
return mBehindFullscreen;
}
跟进ensureActivityConfiguration,在ActivityRecord.ensureActivityConfiguration方法中,有如下代码,
if (changes == 0 && !forceNewConfig) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Configuration no differences in " + this);
// There are no significant differences, so we won't relaunch but should still deliver
// the new configuration to the client process.
if (displayChanged) {
scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
} else {
scheduleConfigurationChanged(newMergedOverrideConfig);
}
return true;
}
displayChanged未改变的前提下,走scheduleConfigurationChange,通知应用进程,
private void scheduleConfigurationChanged(Configuration config) {
if (!attachedToProcess()) {
if (DEBUG_CONFIGURATION) Slog.w(TAG,
"Can't report activity configuration update - client not running"
+ ", activityRecord=" + this);
return;
}
try {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
+ config);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
ActivityConfigurationChangeItem.obtain(config));
} catch (RemoteException e) {
// If process died, whatever.
}
}
至此,应用进程可以根据新配置更新布局等信息。