Context创建过程解析

文章参考《Android进阶解密》一书

一、概述

Context也就是上下文对象,是Android的常用类,Android四大组件都会涉及到Context,比如我们启动Service会调用ContextWrapper以及ContextImpl的startService方法,ContextWrapper以及ContextImpl就是Context的关联类。

二、Context的关联类

Context意为上下文,是一个应用程序环境信息的接口。在我们使用时一般分为两种:

  • 使用Context调用方法,比如启动Activity、访问资源、调用系统级服务等
  • 调用方法时传入Context,比如弹出Toast、Dialog等

Activity、Service、Application都间接地继承自Context,因此我们可以计算出一个应用程序的Context数量,等于Activity和Service的数量加1,1指的是Application数量。

Context是一个抽象类,它的内部定义了很多方法以及静态常量,它的具体实现类为ContextImpl。和Context相关联的类,除了ContextImpl,还有ContextWrapper、ContextThemeWrapper和Activity等,如下图:


image.png

从上图可以看出ContextWrapper、Context继承自Context,ContextWrapper内部包含Context类型的mBase对象,mBase对象只想ContextImpl.ContextImpl提供了很多功能,ContextWrapper是一个装饰类,对ContextImpl进行包装,ContextWrapper主要是起到了方法传递的功能,ContextWrapper几乎所有的方法都是调用ContextImpl的相应方法实现的。ContextThemeWrapper、Activity、Service都继承自ContextWrapper,这样它们就可以通过mBase使用Context的功能了。Activity有主题的相关设置,所以继承了ContextThemeWrapper里面有设置或者gettheme的方法。
Context的关联类采用了装饰模式,主要有以下优点:

  • 使用者可以更方便的使用Context
  • 如果ContextImpl发生改变,不需要修改其它地方的代码
  • ContextImpl的实现不会暴露给使用者,使用者也无需要关心ContextImpl的实现。
  • 通过组合而非继承的方式,拓展ContextImpl的功能,在运行时选择不同的装饰类,实现不同的功能。

下面我们来分别讲解一下个Context的创建过程。

三、Application Context的创建过程

调用getApplicationContext来获取全局的Application Context。应用程序启动完成后,应用程序就会有一个全局的Application Context。我们从应用程序的启动过程开始。
ActivityThread作为应用程序的主线程管理类,它会调用它的内部类ApplicationThread色scheduleLaunchActivity方法来启动Activity

 // we use token to identify this activity without having to send the
        // activity itself back to the activity manager. (matters more with ipc)
        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List pendingResults, List pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);

            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

应用启动以后启动Activity会通过Binder跨进程调用ActivityManagerService(AMS)里面,AMS里面持有ApplicationThread的IBinder引用,跨进程调用scheduleLaunchActivity方法,scheduleLaunchActivity最后通过Handler发送H.LAUNCH_ACTIVITY消息,最后调用ActivityThread的handleLaunchActivity方法。

  private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
            ............
            }
        } else {
            // If there was an error, for any reason, tell the activity manager to stop us.
            try {
                ActivityManager.getService()
                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }

然后调用performLaunchActivity方法

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
        。。。。。。。
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        。。。。。。。
        return activity;
    }

这里简化了一下代码,最后会调用ActivityClientRecord.packageInfo.makeApplication()

  public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            。。。。。。。
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            。。。。。。。。
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
            。。。。。。。。。。。    
            }
        }
        return app;
    }

当mApplication不为null时,直接返回mApplication,如果第一次启动程序mApplication为null,通过ContextImpl.createAppContext来创建ContextImpl。mActivityThread.mInstrumentation.newApplication中传入参数ClassLoader和上面的ContextImpl对象创建Application,然后又将app赋值给ContextImpl的mOuterContext,这样COntext也持有Application的引用了,最后将Application赋值给LoadedApk的mApplication,mApplication就是Application类型的对象。下面的代码就是Application的创建方法:

  static public Application newApplication(Class clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

这里是通过反射来创建Application,并调用了attach方法,将ContextImpl传进去,最后返回该Application。

 /**
     * @hide
     */
    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

这里调用了attachBaseContext(context),在Application的父类ContextWrapper里面调用

  protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

将ContextImpl赋值给mBase,ContextImpl也是Context的实现类,将ContextImpl赋值给ContextWrapper的mBase,这样ContextWrapper就可以用mBase调用Context里面的方法了,而Application继承自ContextWrapper,所以Application也可以调用Context里面的方法了。

四、Activity Context的创建过程

Activity的Context也是在performLaunchActivity方法创建的。

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
     
       。。。。。。
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            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;
                }
                appContext.setOuterContext(activity);
                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);
            }
        }       
        return activity;
    }

首先通过 createBaseContextForActivity(r)创建ContextImpl实例appContext,将创建的Activity设置到ContextImpl的outContext,这样Context里面就可以访问Activity的变量和方法,最后Activity的attach方法,将ContextImpl对象传进去。这后面跟Application差不多,会在Activity的attach方法调用attachBaseContext(context)方法,将ContextImpl复制给ContextWrapper的mBase引用,Activity继承自ContextWrapper,这样Activity就可以调用Context里面的方法了。

五、Service Context的创建过程

Service的Context创建其实跟上面两个差不多,只不过是在Service类里面执行,此处就不过多叙述了。大家自己去看源码就可以了

你可能感兴趣的:(Context创建过程解析)