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

一、Context 关联类

首先Context是一个抽象类,它常见的子类有:Application、Activity、Service、ContextImpl。这些类关系如下:

说明:

  • 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进阶解密》

更多相关文章

  1. Android游戏框架Libgdx使用入门
  2. ContentProvider何时创建?SQLiteDatabase方法何时执行?
  3. 如何在Android(安卓)NDK中调用第三方库文件(.so)
  4. Android之进程通信--Binder
  5. android 简易通讯录查询
  6. 倒计时功能CountDownTimer PK Handler
  7. Android自动生成启动Activity的特定按钮
  8. 创建一个android项目与创建一个android虚拟设备
  9. android开玩笑之创建xml文件

随机推荐

  1. Windows下NDK开发环境搭建,Eclipse+ADT+CD
  2. android 简单快速 倒计时动画
  3. Android第三方异步网路加载库AsyncHttpCl
  4. Android 网络请求的方式
  5. Android(安卓)监听安装和卸载
  6. Android系统调试wifi总结
  7. 三、android编译cmake工程
  8. Android OpenGL 开发
  9. 设置activity为Dialog类型的设置
  10. rtmp/rtsp直播播放器选择