美文网首页
Android中Context理解及创建过程

Android中Context理解及创建过程

作者: MadnessXiong | 来源:发表于2020-04-04 00:11 被阅读0次

    简介:

    Android中四大组件都会涉及到Context。Context意为上下文,是一个应用程序环境信息的接口。Context是一个抽象类,它的内部定义了很多方法及静态常量。

    它的使用场景分为2类:

    • 使用Context调用方法,如启动Activity,访问资源,调用系统服务等。
    • 调用方法时传入Context,比如弹出Toast,创建Dialog等

    Context的关联类:

    Context关联类的关系如下图:


    image-20200403192950842.png

    从上图可知,一个应用程序进程的Context数量等于Activity和Service的总个数加一个Application。

    ContexImpl和ContextWapper都继承自Context。其中ContextWapper内部包含了一个ContextImpl类型的mBase。ContextImpl提供了很多功能,但是外界需要使用并拓展ContextImpl的功能,因此设计上使用了装饰模式,ContextW apper是装饰类,它对ContextImpl进行包装。ContextWapper主要起了方法传递的作用,ContextWapper中几乎所有的方法都是调用ContextImpl的相应方法来实现的。

    ContextThemeWapper,Service和Application都继承自ContextWapper。这样它们都可以使用mBase使用Context的方法。同时它们也是装饰类,在ContextWapper的基础上又增加了不同的功能。ContextThemeWapper中包含和主题相关的方法(如getTheme()),因此需要主题的Activity继承自ContextThemeWapper,而不需要主题的Service和Application都继承自ContextWapper。

    Context的关联类采用装饰模式主要有以下优点:

    • 使用者能够方便地使用Context
    • 如果ContextImpl发生了变化,它的装饰类ContextWapper不需要做任何修改
    • ContextImpl的实现不会暴露给使用者,使用者也不必关心ContextImpl的实现
    • 通过组合而非继承的方式,拓展ContextImpl的功能,在运行时选择不同的装饰类,实现不同的功能

    Context的创建过程

    • Application Context的创建过程:

      在一个应用程序启动完成后,应用程序就可以通过getApplicationContext()获取全局的Application Context。应用程序的启动过程也是根Activity的启动过程,最后会调用performLaunchActivity(),看代码:

           private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
                         //创建Application,这里的r.packageInfo类型为LoadApk
                 Application app = r.packageInfo.makeApplication(false, mInstrumentation);
                 return activity;
             }
      

      可以看到,调用了LoadApk.makeApplication()创建了Application对象,那么看下代码:

             public Application makeApplication(boolean forceDefaultAppClass,
                     Instrumentation instrumentation) {
                         //创建ContextImpl
                     ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
                     //创建Application,并传入ContextImpl类型的appContext
                         app = mActivityThread.mInstrumentation.newApplication(
                             cl, appClass, appContext);
                         //将appLication赋值给ContextImpl
                     appContext.setOuterContext(app); 
                       //将appLication赋值给LoadApk的成员变量mApplication
                     mApplication = app;
                   return app;
             }
      

      可以看到,这里首先创建了ContextImpl对象,然后创建了Application对象。再将appLication赋值给ContextImpl。

      这样ContextImpl就持有了Application的引用。最后将appLication赋值给LoadApk的成员变量mApplication,那么LoadApk就持有了Application Context。

      这里主要关注Application的创建,所以看一下Instrumentation.newApplication():

             static public Application newApplication(Class<?> clazz, Context context)
                     throws InstantiationException, IllegalAccessException,
                     ClassNotFoundException {
                 //创建Application
                 Application app = (Application)clazz.newInstance();
                 //将Application和ContextImpl关联
                 app.attach(context);
                 return app;
             }
      

      这里可以看到,通过反射创建了Application,然后调用了Application.attach(),再看代码:

                final void attach(Context context) {
                //调用父类ContextWapper的attachBaseContext,传入ContextImpl
                 attachBaseContext(context);
             }
      

      这里attachBaseContext()是在父类ContextWapper里实现的,看代码:

             protected void attachBaseContext(Context base) {
                 mBase = base;
             }
      

      到这里就可以看到,将创建的ContextImpl对象赋值给了ContextWapper的mBase。这样ContextWapper以及它的子类就可以通过mBase调用ContextImpl的方法了。

    • Application Context的获取过程

      获取Application Context的获取是通过ContextWapper.getApplicationContext()获取的,那么看代码:

             @Override
             public Context getApplicationContext() {
                 return mBase.getApplicationContext();
             }
      

      上面已经分析出了mBase是ContextImpl,那么继续看它的getApplicationContext():

             public Context getApplicationContext() {
                 return (mPackageInfo != null) ?
                            //调用loadApk的getApplication()
                         mPackageInfo.getApplication() : mMainThread.getApplication();
             }
      

      这里调用了loadApk.getApplication(),看代码:

             Application getApplication() {
                 return mApplication;
             }
      

      前面分析过创建Application后就直接赋值给了LoadApk的成员变量mApplication,所以这里直接返回。

      总结:Application Context在应用程序启动后,创建第一个Activity时创建,创建后赋值给了LoadApk时的成员变量mApplication,同时也创建了ContextImpl,并且将ContextImpl对象赋值给了自身的mBase。在获取Application Context时也是通过获取调用mBase.getApplicationContext(),里面又调用了LoadAPk的getApplication(),获取了之前保存的mApplication。

    • Activity Context的创建过程:

      Activity的Context再Activity的创建过程中被创建,那么还是看performLaunchActivity():

             private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
                         //创建ContextImpl
                 ContextImpl appContext = createBaseContextForActivity(r);
                         //创建activity
                 activity = mInstrumentation.newActivity(
                             cl, component.getClassName(), r.intent);
                         //将activity和ContextImpl关联
                 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);
                 return activity;
             }
      

      可以看到,先创建了ContextImpl,然后创建了Activity,最后通过attach()关联,看一下attach():

             final void attach() {
                 //关联ContextImpl
                 attachBaseContext(context);
      
             }
      

      attachBaseContext()过程和Application里一样,最后还是将ContextImpl赋值给mBase。这样Activity就可以使用ContextImpl的方法了。

    • Service Context的创建过程:

      Service的创建过程也是一样,在创建后调用了attachBaseContext(),将ContextImpl赋值给mBase。这里不再展开。

    相关文章

      网友评论

          本文标题:Android中Context理解及创建过程

          本文链接:https://www.haomeiwen.com/subject/lskrphtx.html