理解Context

   摘自:柯元旦 《Android内核剖析》
Context是什么?
  一个Context意味着一个场景,一个场景就是用户和操作系统交互的一种过程。比如当你打电话、看短信时,场景就包括电话、短信程序对应的界面,以及隐藏在界面后的数据。
  Android程序员把”场景“抽象为Contex类,他们认为用户和操作系统的每一次交互都是一个场景,比如打电话、发短信,这些都是有界面的场景,还有一些没有界面的场景,比如后台运行的服务(Service)。一个应用程序可以认为是一个工作环境,用户在这个工作环境中会切换到不同的场景。
   接下来,从代码方面来看。Activity类的确是基于Context,而Service类也是基于Context.Activity除了基于Context类外,还实现了一些其他重要接口,从设计角度来看,interface仅仅是某些功能,而extends才是类的本质,即Activity的本质是一个Context,其所实现的其他接口只是为了扩充Context的功能而已,扩充后的类称之为一个Acitvity或者Service.
一个应用程序包含多少个Context对象?     
  可以明确的是:
1> 一个Activity就是一个场景(Context),一个Service也是一个场景,所以,应用程序中有多少个Activity或Service,就会有多少个Context对象。
2> Context.getResources()等方法的确返回的是同一个全局对象。

创建Context
1. Application对应的Context
   每个应用程序在第一次启动时,都会首先创建一个Application对象,默认的Application是应用程序的包名,用户可以重载默认的Application.方法是在AndroidManifest.xml的Appliction标签中声明一个新的Application名称,然后在源码中添加该名称的类,该类的父类使用Application类即可。
  程序在第一次启动时,会辗转调用到handleBindApplication()方法中,该方法中有两处创建了ContextImpl对象,但都是在if(data.instrumentationName!=null)条件中。该条件在一般的程序执行时都不会被执行到,只有当创建一个Android Unit Test工程时,相应的Test程序会满足这个条件。
   而如果不是测试工程的话,则调用makeApplication()方法,代码如下:
   Application app=data.info.makeApplication(...);
   而makeApplication()方法中,主要包含以下代码:
ConextImpl  appContext=new ContextImpl();
appContext.init(this,mull,mActivityThread);
app=mActivityThread.mInstrumentation.newApp(cl,appClass,appContext);
appContext.setOuterContext(app);
 即创建一个ContextImpl对象,然后调用init()方法,其中第一个参数this指的就是当前PackageInfo对象,该对象将赋值给ContexxtImpl类中的重要成员变量mPackageInfo.
  这里需要注意,这个PackageInfo对象又是从何而来呢?这就要回溯到是谁调用了makeApplication()方法,回溯流程如下:
   首先,AmS通过远程调用到ActivityThread的bindApplication()方法,该方法的参数包括两种。一种是ApplicationInfo,这是实现了Parcelable接口的数据类,意味着这个对象是由AmS创建的,通过IPC传递到ActivityThread中,另一种是其他相关参数。
     在bindApplication()方法中,会用以上两种参数构造一个本地AppBindData数据类,然后再去调用handleBindApplication().
     在调用handleBindApplication()的时候,AppBindData对象中的info变量还是空值,然后会使用data.info=getPackageInfoNoChecked()方法为info变量赋值,而这个方法的内部实际上会根据AppBindData中的ApplicationInfo中的mPackageName创建一个PackageInfo对象,并把这个对象保存为AcivityThread类的全局对象。显然,一个应用程序中的所有Activity或者Application对象对应的mPackageName都是一样的,即为包的名称,所以ActivityThread中产生一个全局PackageInfo对象。
     接下来,就回到上面所说的调用data.makeApplication()方法了,这就是PackageInfo对象的来源。
2. Activity对应的Context
   启动Activity时,AmS会通过IPC调用到ActivityThread的scheduleLaunchActivity()方法,该方法包含两种参数。一种是ActivityInfo,这是一个实现了Parcelable接口的数据类,意味着该对象是AmS创建的,并通过IPC传递到ActivityThread;另一种是其他参数。
  scheduleLaunchActivity()方法中会根据以上两种参数构造一个本地ActivityRecord数据类,ActivityThread内部会为每一个Activity创建一个ActivityRecord对象,并使用这些数据对象来管理Activity.
     接着会调用到handleLaunchActivity(),然后再调用到performLaunchActivity(),该方法中创建ContextImpl的代码如下:
ContextImpl  appContext=new ContextImpl();
appContext.init(r.packageInfo,r.token,this);
appContext.setOuterContext(activity);
  这个参数r.packageInfo是如何而来的呢?答案如下代码所示:
 ActivityInfo aInfo=r.activityInfo;
 if(r.packageInfo==null){
    r.packageInfo=getPackageInfo(aInfo.applicationInfo,Context.CONTEXT_INCLUDE_CODE);
 }
  即在performLaunchActivity()开始执行时,首先为r.packageInfo变量赋值,getpackageInfo方法的执行逻辑和getPackageInfoNoChecked()基本相同。所以,r.packageInfo对象的PackageInfo对象和Application对应的packageInfo对象是同一个。
3. Service对应的Context
  启动Service时,AmS首先会通过IPC调用到ActivityThread的scheduleCreateService()方法,该方法包含两种参数。一种是ServiceInfo,这是一个实现了Parcelable接口的数据类,意味着该对象是AmS创建的,并通过IPC传递到ActivityThread;另一种是其他参数。
  在scheduleCreateService()方法中,会使用以上两种参数构造一个CreateServiceData的数据对象,ActivityThread会为其所包含的每一个Service创建该数据对象,并通过这些对象来管理Service.
   接着,会执行handleCreateService()方法,其中创建ContextImpl对象的代码如下:
   ContextImpl context=new ContextImpl();
context.init(packageInfo,null,this);
Application app=packageInfo.makeApplication(false...);
  context.setOuterContext(service);
  这与前面的基本相同,调用context.init()方法的第一个参数packageInfo赋值的代码如下:
 PackageInfo  packageInfo=getPackageInfoNOCheck(data.info.applicationInfo);
  赋值代码同样使用了getPackageInfoNOCheck()方法,这意味着Service对应的Context对象内部的mPckageInfo与Activity、Application中是完全相同的。
4. Context之间的关系
  从以上3种情况可以看出,创建Context对象的过程基本上是相同的,包括代码的结构也很相似,所不同的仅仅是针对Application、Activity、Service使用了不同的数据对象。
    实际上一个应用程序包含的Context个数应该为:
 Context个数 = Service个数 + Activity个数 +1
  最后一个1代表的是Application类本身也是对应一个Context对象。
  

  this 与 getApplicationContext() 两种上下文的区别?
① getApplicationContext();生命周期长,只要应用还存活它就存在;
     this 生命周期短,只要 Activity 不存在了,系统就会回收;
② getBaseContext(),getApplication(),getApplicationContext();
    都不能放在 AlertDialog 做上下文;
③ getApplicationContext() 使用场景是比如频繁需要操作的数据库
    推荐用法:Activity.this



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值