Context在android中的作用不言而喻,当我们访问当前应用的资源时,启动一个新的Activity的时候都需要提供Context,而这个Context到底是什么呢。从字面意思是“上下文”,或者也可以叫做环境,场景等,尽管如此,还是有点抽象,从类的继承来说。Context作为一个抽象的基类,它的实现类有
直接子类有ContextImpl,ContextWrapper,MockContext
ContetxImpl和ContextWrapper是继承Context,但是Context抽象方法是在ContextImpl中实现的,ContextWrapper虽然也继承了Context但是其中的方法实现都是交由ContextImpl去完成的。ContextWrapper只是ContextImpl的包装类。
ContetxThemeWrapper,Service,Application都继承了ContextWrapper,所以它们也可以使用mBase调用Context中的方法,它们也是ContextImpl的包装类。
我们再看ContextWrapper的子类有Application,ReceiverRestrictedContext,Service,ContextThemeWrapper,等等
再看ContextThemeWrapper的子类最重要的Activity。
为什么通过任意的Contxet访问资源所得到的都是同一套资源? getApplication和getApplicationContext有什么区别呢?应用中有多少个Context呢?我们一一来分析下:
什么是Context
Context是一个抽象基类,我们通过它访问当前包的资源(getResources,getAssets)和启动其他组件(Service,Broadcast)以及得到各种服务(getSystemService),当然,通过Context能得到的不仅仅只有这些内容,对Context的理解可以来说:Context提供了一个应用的运行环境,在Context的大环境里,应用才可以访问资源,才能完成和其他组件,服务的交互,Context定义了一套基本的功能接口,我们可以理解为一套规范,这套规范实际是被ContextImpl类统一实现的,Activity和Service只是继承并有选择性地重写了某些规范的实现。
Application,Activity和Service作为Context的区别:
首先看下它们的继承关系:选中Service,按下F4键
Activity的继承关系图:
Application的继承关系图:
通过对比可以清晰地发现,Service和Application的类继承关系比较像,而Service和Application还多了一层继承ContextThemeWrapper,这是因为Activity有主题的概念,而Service是没有界面的服务,Application更是一个抽象的东西。
Context的真正实现类都在ContextImpl中,也就是说Context的大部分实现方法调用都会跳转到ContextImpl中,而Service和Application,Activity三者的创建均在ActivityThread中完成,从Activity的启动流程可以了解到,Activity的启动核心过程是在ActivityThread中完成的,这里说明的是,Application和Service的创建也是在ActivityThread中完成的,下面我们来看看三者在创建时是怎么和ContextImpl相关联的。
ActivityThread中的performLaunchActivity方法
可以看出,Activity在创建的之前会new一个ContextImpl对象并在attach方法中关联它。
下面继续看Application对象中ContextImpl的创建:
我们一般通过getApplicationContext来获取系统全局的Application Context,那么Application Context是在哪里创建的呢?
这就要从应用的启动开始,APP启动会调用ActivityThread的内部类ApplicationThread的scheduleLaunchActivity方法来启动
在ApplicationThread的scheduleLaunchActivity方法中向H类发生LAUNCH_ACTIVITY类型的消息,目的是将启动Activity的逻辑放在主线程的消息队列中,这样启动Activity的逻辑会在主线程中执行,在handleMessage()中调用ActivityThread#handleLaunchActivity()
这个又会调用ActivityThread#performLaunchActivity()
会继续调用LoadedApk#makeApplication
分析1语句 创建ContextImpl的对象,其内部之间通过new ContextImpl()进行创建
分析2语句 通过Instrumention的newApplication()创建Application。
分析3语句 将刚创建的Application类型app赋值给LoadedApk类中的成员变量mAppliction,getApplicationContext方法返回就是这个mApplication。
接下来继续分析Instrumention#newApplication()方法
继续看是 getFactory(context.getPackageName()).instantiateApplication(cl, className);去生成Application
可以看到最终是通过反射创建的,再回过头来看Instrumention.newApplication(),在Application创建完成后调用了Application的attach()
继续看Application的attach方法
里面又调用了父类ContextWrapper的attachBaseContext(context)方法,
这样就把刚创建的ContextImpl对象赋值给了ContextWrapper中的mBase。
网友评论