Android深入理解Context--Activity中Context的创建过程

本系列分四篇文章详细介绍Context, 这是第二篇

  • Android深入理解Context–Application中Context的创建过程

  • Android深入理解Context–Activity中Context的创建过程

  • Android深入理解Context–Service中Context的创建过程

  • Android深入理解Context–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中的方法和变量。

  • 注释4activity.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。这是我们应用程序的窗口。

  • 接着看注释3mWindow.setCallback(this), 对window设置了一个回调,这个回调中有很多我们经常使用到的方法,比如onAttachedToWindow,onDetachedFromWindow,dispatchTouchEvent等。

  • 注释4处将给Window中设置了一个WindowManager。

  • 注释5处将Window中刚才设置的WindowManager获取出来赋值给Activity中的成员变量mWindowManager。而Activity中通过getWindowManager()方法获取的WindowManager也就是PhoneWindow中的WindowManager

  • 到此,Activity中的Context创建过程就分析结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值