说起安卓的Context 大家肯定是“既熟悉又陌生”,熟悉是因为startActivity、startService、getApplicationContext等无论是使用Context的方法还是把Context作为参数传递在开发中经常见。陌生是因为貌似工作了两三年对他的认知貌似还停留在如上阶段。这里就探究下这个神奇的Context。

目录

android services 传值 androidcontext传值_应用程序

一、关联类&作用

1、Context的使用场景小结
  • 使用Context的方法,如开启Activty、访问资源、调用系统的Service等。。。
  • 作为参数传入,如弹Toast时、弹Dialog时等。。。
2、简要继承关系图

Context的子类太多啦,这里就挑选出几个重要的类画出继承关系图

android services 传值 androidcontext传值_ide_02

  • Context是一个抽象类,内部定义了一系列子类公用方法。
  • ContextImpl和ContextWrapper继承自Context,ContextImpl 是Context的具体实现类,ContextImpl 提供了很多功能,外界需要使用并拓展ContextImpl的功能,因此设计上使用了装饰模式。ContextWrapper就是装饰者。
  • ContextWrapper是装饰类,它对ContextImpl进行包装,ContextWrapper主要是起了方法传递的作用,ContextWrapper中几乎所有的方法都是调用ContextImpl的相应方法来实现的。
  • ContextThemeWrapper、Service和Application都继承自ContextWrapper,他们都可使用Context的方法,同时它们也是装饰类。
  • ContextThemeWrapper在ContextWrapper的基础上又添加了不同的功能。ContextThemeWrapper中包含和主题相关的方法(比如getTheme方法),因此,需要主题的Activity继承ContextThemeWrapper,而不需要主题的Service继承ContextWrapper。

二、Application Context的创建过程

针对Application我们或许已经了解过他是一个全局的单利,也就是App在一次进程开启到关闭期间他的实例是全局不变的。

一个App首次被开启其实也就是根Activity创建的过程,之前我们就了解过根Activity创建的过程也就是应用程序被开启的过程。所以Application的创建过程还要从ApplicationThread收到AMS的请求开始创建根Activity说起。

时序图

android services 传值 androidcontext传值_上下文_03


ActivityThread 类作为应用程序进程的主线程管理类,它会调用它的内部类ApplicationThread的scheduleLaunchActivity方法来启动Activity,最终发送LAUNCHER_ACTIVITY消息给H类,在H类的handleMessage中进行处理。

H&handleMessage
// H类是ActivityThread的内部类
 private class H extends Handler {
 
        public static final int LAUNCH_ACTIVITY         = 100;
        public static final int PAUSE_ACTIVITY          = 101;
        public static final int PAUSE_ACTIVITY_FINISHING= 102;
        public static final int STOP_ACTIVITY_SHOW      = 103;
        ...
        
  public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    //获取收到的消息对象 ActivityClientRecord 
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                   // 1、ActivityClientRecord的packageInfo 对象类型是LoadedApk.
                   //应用程序进程要启动Activity时需要将该Activity所属的APK加载进来,
                   //而LoadedApk就是用来描述已加载的APK文件的
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                     //2、继续调用ActivityThread的handleLaunchActivity
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                
                ...
}
ActivityThread#handleLaunchActivity&performLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
        // 1、启动activity
        Activity a = performLaunchActivity(r, customIntent);
}

   private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   //1、ActivityInfo:用于存储代码以及AndroidManifes设置的Activity和Receiver
   //节点信息,比如Activity的theme和launchMode
 ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
        //2、获取APK文件的描述类LoadedApk
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
//3、获取要启动的Activity的ComponentName类,
//在ComponentName 类中保存了该Activity的包名和类名
        ComponentName component = r.intent.getComponent();
        ...
        // 4、创建要启动Activity的上下文环境
  ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //5、根据ComponentName中存储的Activity类名,
            //用类加载器来创建该Activity的实例
            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);
            }
        }
        ...
        //6、创建Application,makeApplication 方法内部会调用Application的onCreate方法
  Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    ...

//7、初始化Activity,在attach方法中会创建Window对象(PhoneWindow)并与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);
}

...

activity.mCalled = false;
                if (r.isPersistable()) {
                // 8、调用Instrumentation的callActivityOnCreate方法来启动Activity
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
}

可见Application实例是在根activity实例创建时创建的。具体是通过LoadApk的makeApplication方法创建。

LoadApk#makeApplication
public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
    //1、首次启动应用程序这里mApplication 一定是空的。会走下文的创建。
   if (mApplication != null) {
            return mApplication;
        }

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

        Application app = null;

        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);
            }
            // 2、创建ContextImpl 对象
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);      
            //3、根据类加载器,Application 类名,ContextImpl 对象
            //来创建Application对象
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            //核心:吧创建的Application传递给ContextImpl的成员变量mOuterContext,
            // 这样ContextImpl就包含了Application的引用了。
            appContext.setOuterContext(app);
        }
...

 mActivityThread.mAllApplications.add(app);
 //5、mApplication 为LoadApk的成员变量,mApplication 为Application类型。
 
 // 这里吧创建的Application对象app赋值给mApplication 一份
 //以便于用户获取application时提供
        mApplication = app;

...

return app;
}
Application创建的细节#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 {
            //1、 通过反射获得Application 对象
        Application app = (Application)clazz.newInstance();
        //2、调用Application 的attach方法与Context进行绑定。
        app.attach(context);
        return app;
    }
Application#attach
/**
     * @hide
     */
    /* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

attach方法中调用了attachBaseContext方法,它在Application的父类ContextWrapper中实现

ContextWrapper
public class ContextWrapper extends Context {
    @UnsupportedAppUsage
    Context mBase;

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

这个base就是一路传递过来的ContextImpl对象(参考Instrumentation.newApplication)它是Context的实现类

将ContextImpl赋值给ContextWrapper的Context类型的成员变量mBase,这样ContextWrapper就持有了ContextImpl的引用 ContextWrapper中就可以使用ContextImpl的方法了。也就是说可以使用Context的方法了。

Application的attach方法的作用就是使Application可以使用Context的方法,这样Application才可以用来代表Application Context

三、Application Context的获取

我们经常中用context.getApplicationContext来获取Application Context。

getApplicationContext的具体实现在ContexWrapper类中实现,ContextWrapper是对ContextImpl的装饰,具体的实现在ContextImpl类中

ContextImpl#getApplicationContext
@Override
    public Context getApplicationContext() {
    //mPackageInfo 为LoadApk类型
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }

由于应用程序这时已经启动,因此LoadedApk不会为null,则会调用LoadedApk的getApplication方法

LoadApk#getApplication
Application getApplication() {
        return mApplication;
    }

在Application对象创建的最后一步就是把创建的值在LoadApk的成员变量中保存一份。

灵魂拷问:getApplication 与getApplicationContext的区别?

二者获取的值都是Application对象,只是在使用上有区别,前者是Activity、Service的特有方法。所以在BroadCastReceiver,ContentProvider中无法使用getApplication 来获取Application。后者是Context的方法。四大组件中都可以使用,故BroadCastReceiver,ContentProvider中只能使用getApplicationContext来获取Application。

四、Activity的Context创建过程

想要在Activity中使用Context提供的方法,要先创建Context。Activity的Context会在Activity的启动过程中被创建。

根Activity的启动流程我们已经熟悉,最终AMS会请求ApplicationThread的scheduleLaunchActivity来开启Activity。

时序图

android services 传值 androidcontext传值_ide_04

如上时序图,发送消息,处理消息的调用流程我们都十分熟悉啦这里直接跳过,直接进入
ActivityThread的performLaunchActivity处理流程,这里才是真正的开始

ActivityThread#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   //ActivityInfo:用于存储代码以及AndroidManifes设置的Activity和Receiver
   //节点信息,比如Activity的theme和launchMode
 ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
        //获取APK文件的描述类LoadedApk
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
//获取要启动的Activity的ComponentName类,
//在ComponentName 类中保存了该Activity的包名和类名
        ComponentName component = r.intent.getComponent();
        ...
        // 1、创建 Activity 需要的的上下文环境ContextImpl 对象
  ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //2、根据ComponentName中存储的Activity类名,
            //用类加载器来创建该Activity的实例
            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);
            }
        }
        ...
        //创建Application,makeApplication 方法内部会调用Application的onCreate方法
  Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    ...
    //3、吧activity的实例传递给ContextImpl的成员变量outerContext,
    //这样ContextImpl也可以访问Activity的变量和方法
 appContext.setOuterContext(activity )
//4、初始化Activity,在attach方法中会创建Window对象(PhoneWindow)
//并与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);
}

...

activity.mCalled = false;
                if (r.isPersistable()) {
                // 调用Instrumentation的callActivityOnCreate方法来启动Activity
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }

首先创建ContextImpl 对象appContext,然后把这个对象传入activity的attach方法中

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, ActivityConfigCallback activityConfigCallback) {
        //1、调用ContextThemeWrapper的attachBaseContext方法
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
/*
创建PhoneWindow,它代表应用程序窗口.

PhoneWindow在运行中会间接触发很多事件,比如点击、菜单弹出、屏幕焦点变化等事件,
这些事件需要转发给与PhoneWindow关联的Actvity

转发操作通过Window.Callback接口实现,Actvity实现了这个接口

*/
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        //将当前Activity通过Window的setCallback方法传递给PhoneWindow
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
       ....
        //为PhoneWindow设置WindowManager
        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());
        }
        /*
获取WindowManager并赋值给Activity的成员变量mWindowManager,
这样在Activity中就可以通过getWindowManager方法来获取WindowManager
*/
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;

        mWindow.setColorMode(info.colorMode);
    }
ContextThemeWrapper#attachBaseContext
@Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
    }
ContextWrapper#attachBaseContext
protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

base指的是一路传递过来的Activity的ContextImpl,将它赋值给ContextWrapper的成员变量mBase。这样ContextWrapper就可以装饰ContextImpl的方法了,也即可以使用Context的方法了。

总结:在启动Activity的过程中创建ContextImpl,并赋值给ContextWrapper的成员变量mBase。Activity继承自ContextWrapper的子类ContextThemeWrapper,这样在Activity中就可以使用Context中定义的方法了

Activity&Application 相同注意点:

  • 一路传递过来的ContextImpl 对象
  • 吧实例传递给ContextImpl 的成员变量OuterContext
  • 装饰者模式

五、Service的Context创建过程

Service的Context创建过程与Activity的Context创建过程类似,在Service的启动过程中被创建的。

ActivityThread的内部类ApplicationThread会调用scheduleCreateService方法来启动Service,scheduleCreateService内部通过sendMessage方法向H类发送CREATE_SERVICE类型的消息,H类的handleMessage方法会对CREATE_SERVICE类型的消息进行处理,其中调用了ActivityThread的handleCreateService方法来真正进行创建Service

ActivityThread#handleCreateService
private void handleCreateService(CreateServiceData data) {

        unscheduleGcIdler();
        //获取要启动Service的应用程序的LoadedApk 信息
        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
        // 获取类加载器,创建service 对象。
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        }
        ...
        
 try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            // 1、创建ContextImpl对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            // 吧创建的service对象设置给ContextImpl 的成员变量outerContext
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            // 2、吧创建的ContextImpl 类型对象context 传入service的attach方法中
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
             //调用Service 类对象service启动service       
            service.onCreate();
        // 和Activity类似,启动的组件信息在ActivityThread类的对应成员信息中存储。
            mServices.put(data.token, service);
            //mServices是一个ArrayMap
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
}
Service#attach
public final void attach(
            Context context,
            ActivityThread thread, String className, IBinder token,
            Application application, Object activityManager) {
            //1、调用了ContextWrapper的attachBaseContext方法
        attachBaseContext(context);
        mThread = thread;           // NOTE:  unused - remove?
        mClassName = className;
        mToken = token;
        mApplication = application;
        mActivityManager = (IActivityManager)activityManager;
        mStartCompatibility = getApplicationInfo().targetSdkVersion
                < Build.VERSION_CODES.ECLAIR;
    }

base一路传递过来的是ContextImpl,将ContextImpl赋值给ContextWrapper的Context类型的成员变量mBase,这样在ContextWrapper中就可以使用Context的方法,而Service继承自ContextWrapper,同样可以使用Context的方法

The end

参考:
安卓进阶解密:微信读书版