Context理解
Context
理解为上下文对象,是一个应用程序环境信息的接口,也就是说通过Context
对象来保存应用相关信息。Activity
、Service
、Application
都间接继承自Context
,Context
是一个抽象类,内部定义了很多方法和静态常量,它的具体实现类是ContextImpl
。通过下图了解Context
的体系。
ContextImpl
和ContextWrapper
都继承自Context
,ContextWrapper
内部持有一个具体指向ContextImpl
对象的mBase
变量,两者使用了装饰者模式,ContextWrapper
是装饰者,相关方法的调用最终都会调用ContextImpl
相关方法。
Service
、ContextThemeWrapper
、Application
都继承自ContextWrapper
。由于ContextThemeWrapper
和主题有关,所以Activity
继承了它。这样我们通过Activity
、Service
、Application
上下文的调用基本都委托到ContextImpl
实例的相关方法的调用。
Application Context
的创建
在创建Activity
的时候,会调用ActivtyThread
的performLaunchActivity
函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); }
ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); }
if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } 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) { ...... }
try { Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (r.overrideConfig != null) { config.updateFrom(r.overrideConfig); }
Window window = null; if (r.mPendingRemoveWindow != null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; }
appContext.getResources().addLoaders( app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
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, 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()) { 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); 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; }
|
LoadedApk
对象用于缓存当前加载应用程序相关信息。这里将LoadedApk
对象保存到了ActivityClientRecord
对象的packageInfo
变量。performLaunchActivity
函数涉及到了Activity
和Applcation
的创建。由于这里分析Application
上下文,所以只关心Application
的创建,即调用LoadedApk
的makeApplication
函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { //如果不是第一次调用,直接返回已经创建好的Application实例 if (mApplication != null) { return mApplication; }
Application app = null;
String appClass = mApplicationInfo.className; if (forceDefaultAppClass || (appClass == null)) { appClass = "android.app.Application";//可以看到Application的类名 }
try { final java.lang.ClassLoader cl = getClassLoader(); if (!mPackageName.equals("android")) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "initializeJavaContextClassLoader"); initializeJavaContextClassLoader(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } ...... //创建ContextImpl实例 ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); NetworkSecurityConfigProvider.handleNewApplication(appContext); //创建Application实例 app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); //ContextImpl实例也引用Application实例 appContext.setOuterContext(app); } catch (Exception e) { ...... } mActivityThread.mAllApplications.add(app); //赋值给Application变量 mApplication = app;
if (instrumentation != null) { try { //回调Application的onCreate函数 instrumentation.callApplicationOnCreate(app); } catch (Exception e) { ...... } } return app; }
|
先判断Application
对象mApplication
是否为null
,第一次调用该函数为null
,此时为创建该实例。然后通过ContextImpl.createAppContext
创建出了ContextImpl
的实例,也就是Applicaton Context
。
再通过Instrumentation
对象的newApplication
函数创建出Application
对象,newApplication
函数有两个重载函数,其逻辑最终调用下面两行代码。通过反射创建Application
实例,并调用其attach
函数,并将前面创建好的ContextImpl
实例传递进去。
1 2
| Application app = (Application)clazz.newInstance(); app.attach(context);
|
而在attach
函数中,通过attachBaseContext
函数把context
赋值给了ContextWrapper
的mBase
变量。因为Application
类是ContextWrapper
的子类,这样在创建Application
实例时,其内部就持有了ContextImpl
的对象,从而可以使用ContextImpl
对象相关方法。从而Application
可以用来代表Application Context
。到这里Application Context
就创建完毕了。
1 2 3 4
| final void attach(Context context) { attachBaseContext(context); mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; }
|
而我们平常通过Application
实例getApplicationContext
函数来获取应用的上下文。实际是调用了其父类ContextWrapper
。
1 2 3
| public Context getApplicationContext() { return mBase.getApplicationContext(); }
|
这里的mBase
指的是ContextImpl
实例。
1 2 3 4
| public Context getApplicationContext() { return (mPackageInfo != null) ? mPackageInfo.getApplication() : mMainThread.getApplication(); }
|
由于此时应用已经创建,所以mPackageInfo
不为null
,从而调用LoadedApk
对象的mPackageInfo
的getApplication
函数。
1 2 3
| Application getApplication() { return mApplication; }
|
也就是我们前面创建的Applicaton
对象。
Activity Context
的创建
通过上一节我们知道,在ActivityThread
类的performLauncherActivity
函数会创建Activity
实例和对应的上下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ...... 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) { ...... }
try { ...... 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, r.assistToken);
...... activity.mCalled = false; if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } ... } ... } catch (SuperNotCalledException e) { ... } catch (Exception e) { ... }
return activity; }
|
可以看到整体的逻辑的和Application Context
的创建类似。通过createBaseContextForActivity
函数创建ContextImpl
的实例,通过Instrumentation
类的newActivity
函数创建Activity
对象,然后通过Activity
的对象的attach
函数,将ContextImpl
对象设置到Activity
对象中,通过ContextImpl
类的setOuterContext
函数,将Activity实例设置给ContextImpl
对象,达到两者相互应用,可以调用彼此的方法。
createBaseContextForActivity
函数通过ConextImpl
类方法createActivityContext
创建了ContextImple
实例,createActivityContext
函数也是直接new
一个ContextImpl
实例。
1 2 3 4 5 6 7
| private ContextImpl createBaseContextForActivity(ActivityClientRecord r) { ... ContextImpl appContext = ContextImpl.createActivityContext( this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig); ... return appContext; }
|
接着看Instrumentation
类的newActivity
函数,
1 2 3 4 5 6 7 8
| public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { String pkg = intent != null && intent.getComponent() != null ? intent.getComponent().getPackageName() : null; return getFactory(pkg).instantiateActivity(cl, className, intent); }
|
getFactory
函数。
1 2 3 4 5 6 7 8 9 10 11
| private AppComponentFactory getFactory(String pkg) { if (pkg == null) { return AppComponentFactory.DEFAULT; } if (mThread == null) { return AppComponentFactory.DEFAULT; } LoadedApk apk = mThread.peekPackageInfo(pkg, true); if (apk == null) apk = mThread.getSystemContext().mPackageInfo; return apk.getAppFactory(); }
|
最终还是调用了AppComponentFactory.DEFAULT
的instantiateActivity
函数新建Activity
实例。定位到AppComponentFactory
类的instantiateActivity
函数。直接通过类加载新建了Activity
实例。
1 2 3
| public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,@Nullable Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return (Activity) cl.loadClass(className).newInstance(); }
|
回到Activity
类的attach
函数绑定Context
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| 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) { //注释1 attachBaseContext(context);
mFragments.attachHost(null /*parent*/); //注释2 mWindow = new PhoneWindow(this, window, activityConfigCallback); mWindow.setWindowControllerCallback(mWindowControllerCallback); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } mUiThread = Thread.currentThread();
mMainThread = aThread; mInstrumentation = instr; mToken = token; mAssistToken = assistToken; mIdent = ident; mApplication = application; mIntent = intent; mReferrer = referrer; mComponent = intent.getComponent(); mActivityInfo = info; mTitle = title; mParent = parent; mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; if (voiceInteractor != null) { if (lastNonConfigurationInstances != null) { mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor; } else { mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this, Looper.myLooper()); } }
mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); if (mParent != null) { mWindow.setContainer(mParent.getWindow()); } mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config;
mWindow.setColorMode(info.colorMode); mWindow.setPreferMinimalPostProcessing( (info.flags & ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING) != 0);
setAutofillOptions(application.getAutofillOptions()); setContentCaptureOptions(application.getContentCaptureOptions()); }
|
attach
函数给Activity
对象创建了PhoneWindow
对象,即程序窗口Window
的实现类,并设置了很多回调,这样像点击,焦点等事件都会通过Window
回调到Activity
中。回到Context
分析,通过attachBaseContext
函数设置Context
函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); if (newBase != null) { newBase.setAutofillClient(this); newBase.setContentCaptureOptions(getContentCaptureOptions()); } }
protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); }
protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; }
|
通过向上一层一层的调用,最终还是将ContextImpl
实例设置给了ContextWrapper
的mBase
变量。与Application Context
的设置是一致的。
Service Context
的创建
Service Context的创建可以直接定位到ActivityThread
类的handleCreateService
函数,其逻辑与Activity
或Application
的上下文创建是类似的。感兴趣的同学可以自己分析,当做一个彩蛋。
总结
通过Context
创建的分析,都是创建ContextImpl
的实例,其保存着Application
或者Activity
、Service
相关环境信息,从而被从称为对应的上下文。Context
在一个应用程序的数量,等于Activity
数量+Service
数量+1个Application
数量总和。