Android之Application和Activity的Context区别

总结:

生命周期跟UI相关的,使用Activity的Context处理,如:对话框,各种View,需要startActivity的等。
生命周期跟UI无关的,使用Application的Context,如:AsyncTask,Thread,第三方库初始化等等。

在Activity中,Activity.this和getApplicationContext()返回的不是同一个对象,一个是当前Activity的实例,一个是项目的Application的实例,这两者的生命周期是不同的,它们各自的使用场景不同,getApplicationContext() 生命周期是整个应用,当应用程序摧毁的时候,它才会摧毁;Activity.this的context是属于当前Activity的,当前Activity摧毁的时候,它就摧毁。

Context是什么?
Context是维持Android程序中各组件能够正常工作的一个核心功能类,继承结构图如下:

可以看到Activity、Service、Application都是Context的子类。
通过继承关系可以看到:

  • Context直接子类为ContextIml(具体实现类)和ContextWrapper(上下文功能包装类),而ContextWrapper又有三个子类,分别是ContextThemeWrapper、Service和Application。
  • 由于Activity和Service、Application不在一个继承层级里,而是继承了ContextThemeWrapper。
  • ContextWrapper和ContextThemeWrapper这两个类的名字,区别在Theme。ContextThemeWrapper是一个带主题的封装类,内部包含了主题(Theme)相关的接口,当Activity在启动的时候系统都会加载一个主题,也就是我们在配置文件AndroidManifest.xml里面写的android:theme=”@style/AppTheme”的属性(如下图所示),可是Service和Applicaton并不需要加载主题,因此他们继承自ContextWrapper。


     



再来从源码角度看Context类:

1

2

3

public abstract class Context {

      ......

}

Context是个抽象类,里面定义了各种抽象方法,包括获取系统资源,获取系统服务,发送广播,启动Activity、Service等,结合上图:Activity、Service、Application都是继承自ContextWrapper(上下文功能的封装类),而在ContextWrapper内部会包含一个名为 mBase 的 Context 对象,由这个 mBase 对象去实现了绝大多数的方法:

 
  1. /**

  2. * Proxying implementation of Context that simply delegates all of its calls to

  3. * another Context. Can be subclassed to modify behavior without changing

  4. * the original Context.

  5. */

  6. public class ContextWrapper extends Context {

  7. Context mBase;

  8. /**

  9. * Set the base context for this ContextWrapper. All calls will then be

  10. * delegated to the base context. Throws

  11. * IllegalStateException if a base context has already been set.

  12. *

  13. * @param base The new base context for this wrapper.

  14. */

  15. protected void attachBaseContext(Context base) {

  16. if (mBase != null) {

  17. throw new IllegalStateException("Base context already set");

  18. }

  19. mBase = base;

  20. }

  21. /**

  22. * @return the base context as set by the constructor or setBaseContext

  23. */

  24. public Context getBaseContext() {

  25. return mBase;

  26. }

  27. @Override

  28. public AssetManager getAssets() {

  29. return mBase.getAssets();

  30. }

  31. @Override

  32. public Resources getResources() {

  33. return mBase.getResources();

  34. }

  35. @Override

  36. public ContentResolver getContentResolver() {

  37. return mBase.getContentResolver();

  38. }

  39. @Override

  40. public Looper getMainLooper() {

  41. return mBase.getMainLooper();

  42. }

  43. @Override

  44. public Context getApplicationContext() {

  45. return mBase.getApplicationContext();

  46. }

  47. @Override

  48. public String getPackageName() {

  49. return mBase.getPackageName();

  50. }

  51. @Override

  52. public void startActivity(Intent intent) {

  53. mBase.startActivity(intent);

  54. }

  55. @Override

  56. public void sendBroadcast(Intent intent) {

  57. mBase.sendBroadcast(intent);

  58. }

  59. @Override

  60. public Intent registerReceiver(

  61. BroadcastReceiver receiver, IntentFilter filter) {

  62. return mBase.registerReceiver(receiver, filter);

  63. }

  64. @Override

  65. public void unregisterReceiver(BroadcastReceiver receiver) {

  66. mBase.unregisterReceiver(receiver);

  67. }

  68. @Override

  69. public ComponentName startService(Intent service) {

  70. return mBase.startService(service);

  71. }

  72. @Override

  73. public boolean stopService(Intent name) {

  74. return mBase.stopService(name);

  75. }

  76. @Override

  77. public boolean bindService(Intent service, ServiceConnection conn, int flags) {

  78. return mBase.bindService(service, conn, flags);

  79. }

  80. @Override

  81. public void unbindService(ServiceConnection conn) {

  82. mBase.unbindService(conn);

  83. }

  84. @Override

  85. public Object getSystemService(String name) {

  86. return mBase.getSystemService(name);

  87. }

  88. ......

  89. }

所以,我们在Activity中获取的getBaseContext,实际得到的就是一个ContextImpl对象。 

从上述源码可以看出ContextWrapper中的方法的实现都调用了mBase对象中对应的方法。attachBaseContext()方法其实是由系统来调用的,它会把ContextImpl对象作为参数传递到attachBaseContext()方法当中,从而赋值给mBase对象,之后ContextWrapper中的所有方法其实都是通过这种委托的机制交由ContextImpl去具体实现的,所以说ContextImpl是上下文功能的实现类是非常准确的。

在Android系统中一共有Application、Activity和Service三种类型,在创建Activity、Service、Application时都会自动创建Context,因此如果要统计一个app中Context数量,我们可以这样来表示:
Context数量 = Activity数量 + Service数量 + 1个Application

Application Context中的空指针问题

先看下面两个例子:

 
  1. //第一种使用方式

  2. public class MyApplication extends Application {

  3. public MyApplication() {

  4. String packageName = getPackageName();

  5. Log.d("TAG", "package name is " + packageName);

  6. }

  7. }

  8. //第二种使用方式

  9. public class MyApplication extends Application {

  10. @Override

  11. public void onCreate() {

  12. super.onCreate();

  13. String packageName = getPackageName();

  14. Log.d("TAG", "package name is " + packageName);

  15. }

  16. }

运行结果:第一种使用方式有空指针错误,第二种则运行正常。为什么呢?ContextWrapper中有一个attachBaseContext()方法,只有这个方法会将传入的一个Context参数赋值给mBase对象,在mBase非空后,调用mBase方法才不会崩溃。

Application中方法的执行顺序如下图所示:

Application中在onCreate()方法里去初始化各种全局的变量数据是一种比较推荐的做法,但是如果你想把初始化的时间点提前到极致,也可以去重写attachBaseContext()方法,如下所示:

 
  1. public class MyApplication extends Application {

  2. @Override

  3. protected void attachBaseContext(Context base) {

  4. // 在这里调用Context的方法会空指针错误

  5. super.attachBaseContext(base);

  6. // 在这里可以正常调用Context的方法

  7. }

  8. }

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值