本系列分四篇文章详细介绍Context, 这是第二篇
-
上一节Android深入理解Context讲了源码Application中创建Context,这一节我们说说源码Activity中是如何创建Context的。我们还是从
ActivityThread.performLaunchActivity
中开始分析,如果不太明白这之前的逻辑的话,可以参考Activity启动流程源码分析。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); } //-----1----- ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); //-----2----- 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; } //-----3----- appContext.setOuterContext(activity); //-----4----- 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); } if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onCreate()"); } r.activity = activity; } ... } 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; }
-
注释
1
处创建了一个Activity的ContextImpl。 -
注释
2
处通过mInstrumentation.newActivity
创建了Activity
实例。 -
注释
3
处将activity赋值给ContextImpl的mOuterContext
, 这样我们就可以通过ContextImpl来调用Activity中的方法和变量。 -
注释
4
处activity.attach
是一个很重要的方法,此处将appContext
传入到Activity中,attach
方法如下:@UnsupportedAppUsage 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(this); //-----3----- 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()); } } //-----4----- 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()); } //-----5----- mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; mWindow.setColorMode(info.colorMode); setAutofillOptions(application.getAutofillOptions()); setContentCaptureOptions(application.getContentCaptureOptions()); }
-
在注释
1
处调用了activity.attachBaseContext
,内部代码如下, 而super.attachBaseContext(newBase)
会根据继承关系一直调用到ContextWrapper
, 然后将ContextImpl
类型的Context传进去,赋值给mBase
。public class Activity extends ContextThemeWrapper { @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); if (newBase != null) { newBase.setAutofillClient(this); newBase.setContentCaptureOptions(getContentCaptureOptions()); } } } public class ContextThemeWrapper extends ContextWrapper { @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); } } public class ContextWrapper extends Context { protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; } }
-
这样当我们调用ContextWrapper中的功能时候,实际就交给了
mBase
这个ContextImpl来操作, 我随便截取ContextWrapper中的一段代码就可以看到确实是通过mBase
来处理的:@Override public AssetManager getAssets() { return mBase.getAssets(); } @Override public Resources getResources() { return mBase.getResources(); } @Override public PackageManager getPackageManager() { return mBase.getPackageManager(); } @Override public ContentResolver getContentResolver() { return mBase.getContentResolver(); } @Override public Looper getMainLooper() { return mBase.getMainLooper(); } @Override public Executor getMainExecutor() { return mBase.getMainExecutor(); } @Override public Context getApplicationContext() { return mBase.getApplicationContext(); } @Override public void setTheme(int resid) { mBase.setTheme(resid); } /** @hide */ @Override @UnsupportedAppUsage public int getThemeResId() { return mBase.getThemeResId(); } @Override public Resources.Theme getTheme() { return mBase.getTheme(); } @Override public ClassLoader getClassLoader() { return mBase.getClassLoader(); } @Override public String getPackageName() { return mBase.getPackageName(); } /** @hide */ @Override @UnsupportedAppUsage public String getBasePackageName() { return mBase.getBasePackageName(); } /** @hide */ @Override public String getOpPackageName() { return mBase.getOpPackageName(); } @Override public ApplicationInfo getApplicationInfo() { return mBase.getApplicationInfo(); } @Override public String getPackageResourcePath() { return mBase.getPackageResourcePath(); } @Override public String getPackageCodePath() { return mBase.getPackageCodePath(); } @Override public SharedPreferences getSharedPreferences(String name, int mode) { return mBase.getSharedPreferences(name, mode); }
-
接着看注释
2
处对Window
的初始化,我们发现它的实现类有且仅有PhoneWindow
。这是我们应用程序的窗口。 -
接着看注释
3
处mWindow.setCallback(this)
, 对window设置了一个回调,这个回调中有很多我们经常使用到的方法,比如onAttachedToWindow
,onDetachedFromWindow
,dispatchTouchEvent
等。 -
注释
4
处将给Window中设置了一个WindowManager。 -
注释
5
处将Window中刚才设置的WindowManager获取出来赋值给Activity中的成员变量mWindowManager
。而Activity中通过getWindowManager()
方法获取的WindowManager也就是PhoneWindow中的WindowManager
。 -
到此,Activity中的Context创建过程就分析结束了。