Android 面试总结 - Activity 的 Context 创建过程

815 阅读3分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

Activity 的 Context 创建过程

Activity 在启动过程中被创建。ActivityThread 是应用程序进程的主线程管理类, 最终会通过 ActivityThread 内部类 ApplicationThread 调用 scheduleTransaction 方法,内部又调用了 ActivityThread 的 scheduleTransaction 方法,而 ActivityThread 的 scheduleTransaction 方法是 ActivityThread 的父类 ClientTransactionHandler 中的方法,所以是调用了 ClientTransactionHandler 的 scheduleTransaction 方法,内部又调用 sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction) sendMessage 是抽象方法,由 ActivityThread 实现,故这里 sendMessage 调用到了 ActivityThread 的 sendMessage, ActivityThread 的 sendMessage 在被调用后,会调用 Hanlder 类型 mH 对象的 sendMessage,消息 what 值是上面传下来的 ActivityThread.H.EXECUTE_TRANSACTION,Hanlder 类型 mH 对象在接收到 what 值为 ActivityThread.H.EXECUTE_TRANSACTION 时,会调用 mTransactionExecutor.execute(transaction),在 mTransactionExecutor.execute 内部,调用传入参数 transaction 的 excute 方法,最终执行这个任务。

由 Activity 启动过程中我们知道,transaction 对象其实是 LaunchActivityItem 类型,所以会调用 LaunchActivityItem 的 excute 方法。

public class LaunchActivityItem extends ClientTransactionItem {
    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        // 1
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
        // 2
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
}

LaunchActivityItem 的 excute 方法中,注释 1 处,创建了 ActivityClientRecord 对象,在注释 2 处调用了 ClientTransactionHandler 类型的对象 client 的 handleLaunchActivity 方法,上面分析过,ActivityThread 类继承了 ClientTransactionHandler,ClientTransactionHandler 中的 handleLaunchActivity 方法是抽象方法,所以我们需要看 handleLaunchActivity 方法在 ActivityThread 中的实现。

public final class ActivityThread extends ClientTransactionHandler {

    /**
     * Extended implementation of activity launch. Used when server requests a launch or relaunch.
     */
    @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        ...
        final Activity a = performLaunchActivity(r, customIntent);
        ...
        return a;
    }
}

ActivityThread 的 handleLaunchActivity 方法中调用了 performLaunchActivity 方法

public final class ActivityThread extends ClientTransactionHandler {

    
    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // 1
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            // 2
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
            if (localLOGV) Slog.v(
                    TAG, r + ": app=" + app
                    + ", appName=" + app.getPackageName()
                    + ", pkg=" + r.packageInfo.getPackageName()
                    + ", comp=" + r.intent.getComponent().toShortString()
                    + ", dir=" + r.packageInfo.getAppDir());

            if (activity != null) {
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }

                // Activity resources must be initialized with the same loaders as the
                // application context.
                appContext.getResources().addLoaders(
                        app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
                // 3
                appContext.setOuterContext(activity);
                // 4
                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.configCallback,
                        r.assistToken);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                checkAndBlockForNetworkAccess();
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                if (r.isPersistable()) {
                    // 5
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
                mLastReportedWindowingMode.put(activity.getActivityToken(),
                        config.windowConfiguration.getWindowingMode());
            }
            r.setState(ON_CREATE);

            // updatePendingActivityConfiguration() reads from mActivities to update
            // ActivityClientRecord which runs in a different thread. Protect modifications to
            // mActivities to avoid race.
            synchronized (mResourcesManager) {
                mActivities.put(r.token, r);
            }

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
    }
}

在注释 2 处创建 Activity 的实例,在注释 1 处通过 createBaseContextForActivity 方法来创建 Activity 的 ContextImpl,并将 ContextImpl 传入注释 4 处的 Activity 的 attach 方法中。在注释 3 处调用了 setOuterContext 方法,将此前创建的 Activity 的实例赋值给 ContextImpl 的成员变量 mOuterContext,这样 ContextImpl 也可以访问 Activity 的变量和方法。在注释 5 处 mInstrumentation 的 callActivityOnCreate 方法中会调用 Activity 的 onCreate 方法。

看注释 3 处的 setOuterContext 方法

public final class ActivityThread extends ClientTransactionHandler {

    private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
        ...
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
        ...
        return appContext;
    }
}

调用了 ContextImpl 的 createActivityContext 方法来创建 ContextImpl。
再来看注释 4 处调用的 activity 的 attach 方法

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback,
        AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
        attachBaseContext(context);
        ...
}

activity 的 attach 方法,内部调用了 attachBaseContext 方法,又调用了 ContextThemeWrapper 的 attachBaseContext 方法

public class ContextThemeWrapper extends ContextWrapper {
    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
    }
}

接着又调用了 ContextThemeWrapper 的父类 ContextWrapper 的 attachBaseContext 方法

public class ContextWrapper extends Context {
    Context mBase;
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        // 1
        mBase = base;
    }
}

注释 1 处的 base 是一路传过来的 ContextImpl 对象,赋值给 ContextWrapper 的成员变量 mBase。

总结一下,在启动 Activity 的创建过程中创建 ContextImpl,并赋值给 ContextWrapper 的成员变量 mBase。 Activity 继承自 ContextWrapper 的子类 ContextThemeWrapper,这样在 Activity 中就可以使用 Context 中定义的方法了。