【android】configuration

1,概述

当configuration发生变化后,Activity方法onConfigurationChange会被调用,在此具体记录configuration更新在Framework中的调用过程,直至传入Activity;

2,源码

configuration包含一个应用对手机配置的感知,比如窗口大小、重力方向、手机模式等,可以查看具体成员,

【android】configuration_第1张图片 【android】configuration_第2张图片

 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方法,

【android】configuration_第3张图片

 这个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 

【android】configuration_第4张图片

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.
        }
    }

至此,应用进程可以根据新配置更新布局等信息。

你可能感兴趣的:(android,java,apache)