【Android话题-3.4应用进程】谈谈你对Context的理解

考察内容:

  • 了解Context的作用
  • 熟悉Context的初始化流程
  • 深入理解不同应用组件之间Context的区别

回答几个问题:

  • 应用里面有多少个Context?不同的Context之间有什么区别?
  • Activity里面的this和getBaseContext有什么区别?
  • getApplication和getApplicationContext有什么区别?
  • 应用组件的构造,onCreate、attachBaseContext调用顺序?

Context是一个抽象类

public abstract calss Context{
  public abstract Resources getResources();
  public abstract Object getSystemService(String name);
  public abstract void startActivty(Intent intent);
  public abstract void sendBroadcast(Intent intent);
  ......
}

其实现都在ContextImpl中

class ContextImpl extends Context{
  final ActivityThread mMainThread;  //核心类
  final LoadedApk mPackageInfo;  //安装包信息

  private final ResourcesManager mResourcesManager; //系统资源相关
  private final Resources mResources;

  private Resoures.Theme mThreme = null; //主题相关
  private PackageManager mPackageManager; //包管理
  //系统服务缓存
  final Object] mServiceCache = SystemServiceRegistry.createServiceCache();
}

正是因为有了Context这些应用组件才有意义,它们才能访问系统服务、访问系统资源,如果没有Context那么Activty不过是一个普通的java对象。

Context是在哪里创建的?

哪些组件有自己的Context?

  • Application
  • Activity
  • Service
    (Broadcast、ContentProvider是没有自己的Context的)

Application Context

【Application Context的初始化】:
Application Context是跟随Application一起初始化的,而Application又是跟随应用进程的启动一起初始化的。应用进程的启动是怎样的呢?先是zygote创建应用进程,应用进程启动后会执行一个java类的入口函数,也就是ActivityThread的main函数。这个函数会向AMS报告 :我已经启动好了。AMS收到之后就会下一道命令:创建Application。
AMS让应用创建Application,应用端的处理函数如下:

private void handleBindApplication(AppBindData data){
  //先创建一个Application对象
  Application app = data.info.makeApplication(...);
  //然后调用它的onCreate回调
  app.onCreate();
}

public Application makeApplication(...){
  //先创建一个Context:实现就是newContextImpl(...)
  ContextImpl appContext = ContextImpl.createAppContext(...);
  Application app;
  //然后再创建Application对象,传入appContext参数
  app = mActivityThread.mInstrumentation.newApplication(appContext);
  return app;
}

//创建Application对象:
application newApplication(ClassLoader cl, String className, Context context){
  //先用classLoader对加载Application类
  return newApplication(cl.loadClass(className), context);
}

Application newApplication(Class<?> clazz, Context context){
  //然后再调用newInstance
  //newInstance就会去调用类的构造函数,从而得到Application对象
  Application app = (Application)clazz.newInstance();
  //最后结app附上context
  app.attach(context); //将调用attachBaseContext(context);
  return app;
}

【Application的继承关系】:

public class Application extends ContextWrapper{
  ......
}

public class ContextWrapper extends Context{
  Context mBase;
  
  protected void attachBaseContext(Context base){
    mBase = base;
  }
 
  public Context getBaseContext(){
    return mBase;
  }

  @Overrid
  public Resources getResources() {
    return mBase.getResources();
  }
 
  @Override
  public Object getSystemService(String name) {
    return mBase.getSystemService(name);
  }
 
  @Override
  public void startActivity(Intent intent) {
    mBase.startActivity(intent);
  }
}

Application本身就是一个Context,怎么里面还包了一个Context呢?这是为什么呢?我们可以看到关于Context的所有调用其实都转手丢给了里边的mBase对象,这是一个典型的静态代理模式。如果我们用反射换掉了里面的mBase对象会怎样呢?比如调用getSystemService函数,结果有可能会跳转到另一个Context的实现里面,它就可以对返回的SystemService管理对象做一些手脚。这个机制一般在插件里会用到。

【Application的结论】:

  • 继承关系:Application<-ContextWrapper<-context
  • 调用顺序:->attachBaseContext->onCreate
  • ContextWraper里面包含一个Context,调用都委托给它了

Activity Context

【Activty Context的初始化】:
Activity的Context是跟随Activity的启动的时候一起初始化的:

private Activity performLaunchActivity(){
  Activity activity = null;
  //创建Actvity对象
  activity mInstrumentation.newActivity();
  //获取之前创建好的application
  Application app = r.packageInfo.makeApplication();
  //为Activity创建一个Context:实现就是new ContextImpl()
  Context appContext = createBaseContextForActivity(r, activity);
  //把appContext和application附给activity
  activity.attach(appContext, app, ...); //将调用attachBaseContext(context);
  //调用Activity的生命周期函数
  activity.onCreate();
  return activity;
}

public Activity newActivity(ClassLoader cl, String className){
  //先用ClassLoader加载Activity类,然后用newInstance就会去调用Acivity的构造函数,从而得到Activity的对象
  return (Activity)cl.loadClass(className).newInstance();
}

【Activty的类继承关系】:

public class Activity extends ContextThemeWrapper{
  ...
}

public class ContextThemeWrapper extends ContextWrapper{
  private int mThemeResource;
  private Resources.Theme mTheme;
  private LayoutInflater mInflater;
  private Configuration mOverrideConfiguration;
  private Resources mResources;
}

public class ContextWrapper extends Context{
  Context mBase;
  ......
}

【Activity的结论】:

  • Activity<-ContextThemeWrapper<-ContextWrapper
  • 调用顺序,->attachBaseContext->onCreate

Service Context

【Service Context的初始化】:

private void handleCreateService(CreateServiceData data) {
  Servie service = null;
  //通过classLoader加载Service的类,然后调用newInstance
  //newInstance将调用Service的构造函数从而获得一个Service对象
  servie = (Service)cl.loadClass(data.info.name).newInstance();
  //创建一个Context:实现就是new ContextImpl(...)
  ContextImpl context = ContextImpl.createAppContext(this, packageInfo)
  context.setOuterContext(service);
  //获取之前创建的application对象
  Application app = packageInfo.makeApplication();
  //把context和application附给service
  service.attach(context, app); //将调用attachBaseContext(context);
  //调用Service生命周期
  servcie.onCreate();
}

【Service的继承关系】:

public abstract class Service extends ContextWrapper{
  ......
}

BroadcastReceiver

public abstract class BroadcastReceiver {
  public abstract void onReceive(Context context, Intent intent);
  ......
}

【广播结论】:
广播是一个抽象类,它没有继承Context抽象类,也没有关于Context的全局变量,只有一个onReceive抽象函数,而且这个函数带了一个参数:Context。如果是动态注册的广播,那么这个Context就是用context.registeReceiver注册广播时所用的context;如果是静态注册 的广播,它也不是Activty Context,而是以Application为mBase的ContextWrapper。

ContentProvider

public abstract class ContentProvider {
  private Context mContext = null;
  ......
}

ContentProvider跟广播一样,也没有继承什么ContextWrapper,不过它里面有一个mContext成员变量,它是ContextProvider初始化的时候外面传进来的,传的是Application Context。随便提一下:ContentProvider的初始化虽然是在Application的构造函数以及attachBaseContext之后,但是它是在application.onCreate()之前调用的。也就是说ContentProvider它的onCreate是比application.onCreate要早。

回答几个问题:

  • 应用里面有多少个Context?不同的Context之间有什么区别?
    a)Activty的数个+Service的个数+Application的个数。应用可能是多进程的,因此Application可能有多个。区别:Activty因为要显示UI,因此它继承了ContextThemeWrapper,而Service和Application这种非UI组件则直接继承ContextWrapper。
  • Activity里的this和getBaseContext有什么区别?
    答:因为Activty是继承了Context,所以this就是返回Activity对象自己;而getBaseContext返回的是ContextWrapper里面的mBase。
  • getApplication和getApplicationContext有什么区别?
    答:getApplicationContext()是context里的一个抽象函数,而getApplication()是Activty和Service里特有的——它在别的地方不能用,比如在广播的onReciever(context)中的context是不能调getApplication()的,只能调getApplicationContext()。
  • 应用组件的构造,onCreate、attachBaseContext调用顺序?
    答:组件构造函数->attachBaseContext->onCreate

回归:谈谈你对Context的解理

  • 说清楚Context的作用
    a)Context是应用的上下文,有了Context应用组件就方便去访问系统资源、调用系统服务
  • 说出应用中有几种Context,各自继承关系
  • 说一下Context的初始化流程
发布了114 篇原创文章 · 获赞 27 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/menghaocheng/article/details/104460543