Android Context源码解析

初识Context

对于Android开发者来说,Activity应该是接触到最早的四大组件之一。Activity可以渲染layout生成控件,可以获取图片资源、文本资源、动画资源等等,还可以启动另一个Activity,启动一个后台的Service。每个Activity都有一个Context,通过这个Context我们几乎可以做任何我们想做的事情。比如通过context.getSystemService(name)我们可以获取到Android的内部服务,通过LayoutInflater.from(context)可以加载布局,通过context.getString(resId)可以获取资源。Context在我们的学习初期,它几乎是万能的。

再后来一些,我们知道了Service,Application内部也有一个Context。然后我们知道了Service是后台的服务,它与Activity的最大的区别就是没有界面。Application在一个应用程序中只有一个。

直到有一天我们有可能被问到Activity、Service、Application它们都是Context的子类,它们有什么区别吗?Dialog构造函数中的Context 可以传Application的Context吗?一开始我们是答不上来的。于是我们翻开源码开始探究Context的实现原理

Context源码解析
Context类图


image.png

Context和Context子类的源码

1. Context源码

frameworks/base/core/java/android/content/Context.java

public abstract class Context {
    public abstract AssetManager getAssets();
    public abstract Resources getResources();
    public abstract SharedPreferences getSharedPreferences(File file, int mode);
    public abstract Context getApplicationContext();
    public abstract void startActivity(Intent intent);
    public abstract ComponentName startService(Intent service);
    public abstract Intent registerReceiver(BroadcastReceiver receiver,IntentFilter filter);

    public final String getString(@StringRes int resId) {
        return getResources().getString(resId);
    }
    public final CharSequence getText(@StringRes int resId) {
        return getResources().getText(resId);
    }

    public final Drawable getDrawable(@DrawableRes int id) {
        return getResources().getDrawable(id, getTheme());
    }

    ...省略其他方法
}

在Context.java中,我列举出了一些大家经常用到的方法,它们基本上都是抽象方法。看来真正实现了这些方法的Context并不是Context类本尊啊。我们沿着类图的右边继续阅读源码。

2. ContextWrapper源码

frameworks/base/core/java/android/content/ContextWrapper.java

public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }


    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }


    public Context getBaseContext() {
        return mBase;
    }

    public abstract AssetManager getAssets(){
        return mBase.getAssets();
    }
    ...省略其他方法
}

我这里选取getAssets()方法作为一个代表,其余的类似方法其实也是一样,篇幅有限故省略不表。对比下ContextWrapper和Context类。他们的区别有

ContextWrapper是Context的子类
ContextWarpper多了一个成员变量Context mBase
ContextWrapper多了一个构造函数和attachBaseContext(Context base),他们都是给mBase赋值
Context中定义的抽象方法getAssets()在ContextWrapper中被实现了
ContextWrapper中的方法比如getAssets()、getResource()都是通过调用mBase对象的相关方法来实现的。那么mBase到底是什么,是Context类的实例吗?不是!是Activity、Service、Application吗?不是(因为这些类中,也没有getAssets的具体实现)!那就只能是左边的ContextImpl了。接下来我们看看ContextImpl的源码,看看是否它就是ContextWrapper的mBase。

3. ContextImpl源码

frameworks/base/core/java/android/app/ContextImpl.java

class ContextImpl extends Context{
    final ActivityThread mMainThread;
    final LoadedApk mPackageInfo; 
    private final IBinder mActivityToken
    private final String mBasePackageName;
    private final String mOpPackageName;
    private final @NonNull ResourcesManager mResourcesManager;
    private final @NonNull Resources mResources;
    private Context mOuterContext;
    private int mThemeResource = 0;
    private Resources.Theme mTheme = null;
    private PackageManager mPackageManager;

    @Override
    public AssetManager getAssets() {
        return getResources().getAssets();
    }

    @Override
    public Resources getResources() {
        return mResources;
    }

    @Override
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }

        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }

     @Override
    public void startActivity(Intent intent) {
        warnIfCallingFromSystemProcess();
        startActivity(intent, null);
    }

    @Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();

        // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
        // generally not allowed, except if the caller specifies the task id the activity should
        // be launched in.
        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                && options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }
}

首先我们来看下我们常用的一些方法getAssets()、getResource()、getPackageManager()、startActivity(Intent intent),它们在ContextImpl类中都有了具体的实现。可以片面的确定ContextWrapper的mBase指向的就是ContextImpl的实例对象!!!注意这里只是片面的推断后面还会有更科学、更有理有据、更严肃的推断。大家先记住这个结论就好了,暂时记作不严谨的结论吧。后面会用事实证明

接下来我们看下几个ContextImpl字段。

ActivityThread mMainThread这个顾名思义好像是Activity的线程啊?其实不是!从源码来看它并不继承于Thread
frameworks/base/core/java/android/app/ActivityThread.java

public final class ActivityThread {

    private ContextImpl mSystemContext;

    static volatile IPackageManager sPackageManager;
    final ApplicationThread mAppThread = new ApplicationThread();
    final Looper mLooper = Looper.myLooper();
    final H mH = new H();
    final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
    // List of new activities (via ActivityRecord.nextIdle) that should
    // be reported when next we idle.
    ActivityClientRecord mNewActivities = null;
    // Number of activities that are currently visible on-screen.
    int mNumVisibleActivities = 0;
    ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>();
    private int mLastSessionId;
    final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
    AppBindData mBoundApplication;
    Profiler mProfiler;
    int mCurDefaultDisplayDpi;
    boolean mDensityCompatMode;
    Configuration mConfiguration;
    Configuration mCompatConfiguration;
    Application mInitialApplication;
    final ArrayList<Application> mAllApplications
            = new ArrayList<Application>();
}

1. ContextImpl mSystemContext这个是系统应用才会有的。具体干嘛用的暂时还不知道
2. ApplicationThread mAppThread,mAppThread是用来和ActivityManagerService端的ApplicationThreadProxy通信的。他是Binder的子类。是IPC通信的服务端。当ActivityManagerService对Activity做了相应处理的时候,客户端程序需要通过mAppThread来做相应的处理。比如生成或控制Activity、Service、Application的生命周期
3. Looper mLooper是android应用程序的主looper
4. ArrayMap<IBinder, ActivityClientRecord> mActivities 当前应用程序所有的Activity在客户端的记录
5. int mNumVisibleActivities当前可见的Activity数量
6. ArrayMap<IBinder, Service> mServices = new ArrayMap<>()当前应用程序所有的Service在客户端的记录
7. H mH = new H(),H extends Handler mH就是一个Handler,mH是和主线程的Looper绑定的,换言之就是mH的handleMessage()是在主线程执行的。ApplicationThread的方法是在Binder线程池中执行的。在Binder线程中启动Activity需要用mH切换到主线程中执行。由于启动Activity不是本文的讲解范围,就不费过多笔墨了。
8. ActivityThread在一个应用程序中只有一个实例。但是如果应用程序开启了多进程模式,ActivityThread可能会有多份。比如Service指定android:process为:another。

LoadedApk mPackageInfo这个是用来记录Apk信息的。LoadedApk是在ActivityThread的handleBindApplication()方法中被创建
frameworks/base/core/java/android/app/ActivityThread.java

 private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
            boolean registerPackage) {
        final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
        synchronized (mResourcesManager) {
            WeakReference<LoadedApk> ref;
            if (differentUser) {
                // Caching not supported across users
                ref = null;
            } else if (includeCode) {
                ref = mPackages.get(aInfo.packageName);
            } else {
                ref = mResourcePackages.get(aInfo.packageName);
            }

            LoadedApk packageInfo = ref != null ? ref.get() : null;
            if (packageInfo == null || (packageInfo.mResources != null
                    && !packageInfo.mResources.getAssets().isUpToDate())) {
                if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
                        : "Loading resource-only package ") + aInfo.packageName
                        + " (in " + (mBoundApplication != null
                                ? mBoundApplication.processName : null)
                        + ")");
                packageInfo =
                    new LoadedApk(this, aInfo, compatInfo, baseLoader,
                            securityViolation, includeCode &&
                            (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);

                if (mSystemThread && "android".equals(aInfo.packageName)) {
                    packageInfo.installSystemApplicationInfo(aInfo,
                            getSystemContext().mPackageInfo.getClassLoader());
                }

                if (differentUser) {
                    // Caching not supported across users
                } else if (includeCode) {
                    mPackages.put(aInfo.packageName,
                            new WeakReference<LoadedApk>(packageInfo));
                } else {
                    mResourcePackages.put(aInfo.packageName,
                            new WeakReference<LoadedApk>(packageInfo));
                }
            }
            return packageInfo;
        }
    }

从源码中我们可以知道,LoadedApk是保存在WeakReference中。如果获取到为null就重新生成LoadedApk

  1. IBinder mActivityToken是WindowManager的远程代理对象

  2. Activity、Service、Appplication
    前面我们讲了ContextWrapper的Context mBase指向的是具体的ContextImpl对象。而Activity、Service、Application也都是ContextWrapper的直接子类或间接子类。mBase是通过attachBaseContext(Context context)来赋值的。

通读Activity、Service、Application的源码。发现attachBaseContext方法会在attach方法中被调用

1. Activity源码

frameworks/base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback {
        ...省略其他
        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);//1

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        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;
        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;
    }
}

注释1处说明会通过attachBaseContext(context)把真正的context赋值给mBase。那么顺着调用Activity的attach方法。发现调用者为ActivityThread的handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason)

frameworks/base/core/java/android/app/ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...省略其他
     Activity a = performLaunchActivity(r, customIntent);
    ...省略其他

}

接着看ActivityThread的performLaunchActivity(r,customIntent)方法,由于方法比较长我会在代码里写注释讲解

frameworks/base/core/java/android/app/ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");

        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);
        }

        Activity activity = null;
        try {
            //获取Android程序的ClassLoader mark0
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            //通过反射创建activity.此时Context mBase还没有被赋值
            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对象,如果存在直接返回,如果不存在则生成,
            //mark1 接下来讲解Application的时候会讲到
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (activity != null) {
                //创建给Activity使用的ContextImpl 
                //mark2
                Context appContext = createBaseContextForActivity(r, activity);
                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;
                }
                //通过activity的attach方法把生成的appContext赋值给Activity
                //mark3
                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);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                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;
                r.stopped = true;
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPostCreate()");
                    }
                }
            }
            r.paused = true;
            //把ActivityClientRecord存储到ArrayMap中。在handleResumeActivity中通过token获取mActivities中的ActivityClientRecord
            //mark4
            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;
    }

以上代码与本文讲解Context相关总结如下

  1. mark0 通过反射生成Activity
  2. mark1 通过反射生成Application
  3. mark2 调用ActivityThread的createBaseContextForActivity生成ContextImpl
  4. mark3 并通过Activity.attach赋值给Activity的mBase。这里就完美回答了上面关于ContextImpl源码处的那个不严谨的结论
  5. mark4 把ActivityClientRecord记录到ArrayMap中

mark2处 createBaseContextForActivity源码如下

frameworks/base/core/java/android/app/ActivityThread.java

 private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        int displayId = Display.DEFAULT_DISPLAY;
        try {
            displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, r.token, displayId, r.overrideConfig);//1
        appContext.setOuterContext(activity);//2
        Context baseContext = appContext;

        final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
        // For debugging purposes, if the activity's package name contains the value of
        // the "debug.use-second-display" system property as a substring, then show
        // its content on a secondary display if there is one.
        String pkgName = SystemProperties.get("debug.second-display.pkg");
        if (pkgName != null && !pkgName.isEmpty()
                && r.packageInfo.mPackageName.contains(pkgName)) {
            for (int id : dm.getDisplayIds()) {
                if (id != Display.DEFAULT_DISPLAY) {
                    Display display =
                            dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
                    baseContext = appContext.createDisplayContext(display);
                    break;
                }
            }
        }
        return baseContext;
    }

//1 处通过ContextImpl createActivityContext生成ContextImpl。对应的还有两个类似的方法ActivityThread mainThread和createAppContext(ActivityThread mainThread, LoadedApk packageInfo)。后面我把它们放在一起对比。更容易了解到差别
//2 处给ContextImpl设置了outerContext。这里outerContext就是Activity。归纳总结就是Activity的mBase的outerContext就是Activity本身。Service的mBase的outerContext就是Service本身。Application的mBase的outerContext就是Application本身。是不是有点拗口。

2. Application 创建源码

Application创建地方有两处

1.第一处在前面mark1处,通过makeApplication创建Application

    //r.packageInfo为 frameworks/base/core/java/android/app/LoadedApk
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);

frameworks/base/core/java/android/app/LoadedApk

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

        Application app = null;

        //如果AndroidManifest中没有声明Application用默认的
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            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);
            }
            //mark1 创建Applicaiton的ContextImpl对象
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //mark2 通过反射生成Applicaiton对象并attach(appContext)
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            //mark3 设置outerContext
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }

        // Rewrite the R 'constants' for all library apks.
        SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
                .getAssignedPackageIdentifiers();
        final int N = packageIdentifiers.size();
        for (int i = 0; i < N; i++) {
            final int id = packageIdentifiers.keyAt(i);
            if (id == 0x01 || id == 0x7f) {
                continue;
            }

            rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        return app;
    }

生成Applicaiton总结如下
mark1 创建Applicaiton的ContextImpl对象
mark2 通过反射生成Applicaiton对象并attach(appContext)
frameworks/base/core/java/android/app/Instrumentation

 static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

2.第二处在ActivityThread的handleBindApplication()中,这里才是Application第一次被创建的地方

private void handleBindApplication(AppBindData data) {
    ...省略其他代码

    //和前面讲解的一样
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
    ...省略其他代码
}

mark3 设置outerContext
Application源码如下

public class Application extends ContextWrapper implements ComponentCallbacks2 {

    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
}

3. Service 创建源码

Service部分源码如下

public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
    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;
    }
}

ActivityThread的handleCreateService()会创建Service
frameworks/base/core/java/android/app/ActivityThread.java

private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        //mark1 反射生成Service对象
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            //mark2 生成ContextImpl 和Application一样
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            //确保Application已经生成
            Application app = packageInfo.makeApplication(false, mInstrumentation);

            //mark3 调用service的attach方法
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }

Service创建总结如下

反射生成Service对象
生成ContextImpl 和Application一样
调用service的attach方法

  1. ContextImpl的createActivityContext和createAppContext区别
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread,
                packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
}
//    performLaunchActivity
static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
    if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
    return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
                null, overrideConfiguration, displayId);
}

对比以上代码发现,他们的方法参数的差别在IBinder activityToken。而activityToken其实是与界面相关的。如果用Application或者Service创建Dialog是会报错的。原因就是没有activityToken

4. Dialog报错模拟

public class TestDialogActivity extends Activity{
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        new Dialog(getApplicationContext()).show();//要报错
        new Dialog(this).show();//不报错
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容