Android(安卓)Context 相关
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 是在应用程序启动的时候创建的。
在应用程序的启动过程中,会调用 ActivityThread
的 performLaunchActivity
方法来启动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
对象。查看LoadedApk
的makeApplication
方法:
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方法胡参数,并调用Instrumentation
的 newApplication
创建 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
的实例,并调用Application
的attach
方法将ContextImpl
传入。
4、Application & attach
/* package */ final void attach(Context context) { attachBaseContext(context); mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; }
调用ContextWrapper
的 attachBaseContext
方法
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()
获得Application
的Context
对象。
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; }
mApplication
在 makeApplication
方法中已经赋值,所以这里就得到了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);... }
继续调用ContextThemeWrapper
的attachBaseContext
@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启动过程会调用ActivityThread
的 handleCreateService
来启动 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游戏框架Libgdx使用入门
- ContentProvider何时创建?SQLiteDatabase方法何时执行?
- 如何在Android(安卓)NDK中调用第三方库文件(.so)
- Android之进程通信--Binder
- android 简易通讯录查询
- 倒计时功能CountDownTimer PK Handler
- Android自动生成启动Activity的特定按钮
- 创建一个android项目与创建一个android虚拟设备
- android开玩笑之创建xml文件