Android Context 相关

Context 是上下文环境对象,在Android中经常会使用到。

一、Context 关联类

首先Context是一个抽象类,它常见的子类有:Application、Activity、Service、ContextImpl。这些类关系如下:
Android Context 相关_第1张图片
说明:

  • ContextImpl:
    1、 Application、Activity、Service通过attach() 调用父类ContextWrapper的attachBaseContext(),将父类的成员变量mBase 赋值为ContextImpl对象
    2、ContextWrapper的核心工作都是交给mBase(即ContextImpl)来完成的

二、Application Context 的创建

我们通过getApplicationContext()可以获得一个全局的Context,那么 Application Context 在什么时候创建的呢?很明显全局的Application Context 是在应用程序启动的时候创建的。

在应用程序的启动过程中,会调用 ActivityThreadperformLaunchActivity 方法来启动Activity。

1、ActivityThread & performLaunchActivity

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
		...
		Application app = r.packageInfo.makeApplication(false, mInstrumentation);
		...
		return activity;

该方法会调用 r.packageInfo.makeApplication(即LoadedApk的makeApplication方法) 创建一个Application对象。查看LoadedApkmakeApplication方法:

2、LoadedApk & makeApplication

    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        //如果已经创建则直接返回
        if (mApplication != null) {
            return mApplication;
        }

        Application app = null;
       	try {
            java.lang.ClassLoader cl = getClassLoader();
			...
			//创建 ContextImpl
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //创建 Application 
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
			...
        }
        mActivityThread.mAllApplications.add(app);
        //赋值
        mApplication = app;
		...
        return app;

该方法会创建一个ContextImpl 对象 appContext 作为newApplication方法胡参数,并调用InstrumentationnewApplication 创建 Application 对象。
3、Instrumentation & newApplication

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }
    
    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

该方法会使用newInstance()获得 Application的实例,并调用Applicationattach方法将ContextImpl传入。

4、Application & attach

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

调用ContextWrapperattachBaseContext 方法

5、ContextWrapper & attachBaseContext

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

经过层层传递,到这里就完成了Context的赋值。这里的base也就是传递的ContextImpl对象。

三、Application Context 的获取

我们可以通过getApplicationContext()获得ApplicationContext对象。

1、ContextWrapper & getApplicationContext()

    @Override
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }

mBase 是 ContextImpl 的实例。

2、ContextImpl & getApplicationContext()

    @Override
    public Context getApplicationContext() {
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }

mPackageInfo 也就是 LoadedApk 对象,由于程序已经启动所以此时mPackageInfo 不为null。执行mPackageInfo.getApplication()

3、LoadedApk & getApplication()

  Application getApplication() {
        return mApplication;
    }

mApplicationmakeApplication方法中已经赋值,所以这里就得到了Application 的 Context

四、Activity Context 创建过程

Activity 中使用的 Context 会在 Activity 的启动过程中创建。在Activity的启动流程 中我们知道,ActivityThread 会调用 performLaunchActivity 方法来启动一个 Activity。

1、ActivityThread & performLaunchActivity

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 			...
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, 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);
            ...            
           	return activity;
    }
  • 该方法会调用createBaseContextForActivity创建Context对象
  • 调用activity.attach方法将创建的Context赋值给Activity自己的Context。

2、ActivityThread & createBaseContextForActivity

    private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
		...
		
        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.token, displayId, r.overrideConfig);
        appContext.setOuterContext(activity);
        Context baseContext = appContext;
		...
        return baseContext;
    }

可以看到该方法会创建ContextImpl 对象并返回。

3、Activity & attach


    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) {
            
        attachBaseContext(context);
		...
    }

继续调用ContextThemeWrapperattachBaseContext

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
    }

ContextThemeWrapper 继承 ContextWrapper。

4、ContextWrapper & attachBaseContext

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

到这里就完成了Activity的Context创建。此时mBase 被赋值就是在上面创建在的ContextImpl对象。

五、Service Context 的创建过程

和Activity中Context创建是类似的,Service中Context的创建也是在Service启动过程中创建的。在 Service启动流程 中我们知道在Service启动过程会调用ActivityThreadhandleCreateService 来启动 Service

1、ActivityThread & handleCreateService

    private void handleCreateService(CreateServiceData data) {
		...
       try {
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
        } catch (Exception e) {
           ...
        }
    }

该方法中首先也会创建一个ContextImpl 类型的 context,然后调用service的attach方法将ContextImpl类型的context传入。

2、Service & attach

    public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
        attachBaseContext(context);
        mThread = thread;           // NOTE:  unused - remove?
        mClassName = className;
        mToken = token;
        mApplication = application;
        mActivityManager = (IActivityManager)activityManager;
        mStartCompatibility = getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.ECLAIR;
    }

继续执行attachBaseContext方法

3、ContextWrapper & attachBaseContext

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

ContextImpl类型的Context赋值给mBase,到此就完成了Service中Context的创建。

参考:《Android进阶解密》

你可能感兴趣的:(Android进阶)