目录
- 思维导图
- Context 类层次
- Context 作用以及作用域
- ContextWrapper、ContextImpl、ContextThemeWrapper
- 常见问题汇总
- 参考
思维导图
Context 类层次
Context 作用以及作用域
作用:
看接口就能看出来。
public abstract class Context {
public abstract AssetManager getAssets();
public abstract Resources getResources();
public abstract PackageManager getPackageManager();
public abstract ContentResolver getContentResolver();
public abstract Looper getMainLooper();
public Executor getMainExecutor() {
return new HandlerExecutor(new Handler(getMainLooper()));
}
public abstract Context getApplicationContext();
//...
}
作用如下:
- 四大组件的交互,包括启动 Activity、Broadcast、Service,获取 ContentResolver 等
- 获取系统 / 应用资源,包括 AssetManager、PackageManager、Resources、SystemService 以及 color、string、drawable 等
- 文件、SharedPreference、数据库相关
- 其他辅助功能,比如设置 ComponentCallbacks,即监听配置信息改变、内存不足等事件的发生
作用域:
虽然 Context 神通广大,但是并不是随便拿到一个 Context 实例就可以为所欲为,还是有一些限制的。在绝大多数场景下,Activity、Service 和 Application 这三种类型的 Context 都是通用的,不过也有几种场景比较特殊,比如启动 Activity、弹出 Dialog。Android 是不允许 Activity 或 Dialog 凭空出现的,一个 Activity 的启动必须建立在另外一个 Activity 的基础之上,也就以此形成任务栈。而 Dialog 则必须在一个 Activity 的上面弹出(除非是 System Alert 类型的 Dialog),因此在这种场景下,我们只能使用 Activity 类的 Context。
所以,最常见的错误场景就是:
-
使用 ApplicationContext 去启动一个 LaunchMode 为 standard 的 Activity
会报错,因为非 Activity 类型的 Context 没呀所谓的任务栈。
ContextWarpper、ContextImpl、ContextThemeWrapper
ContextWrapper 是 Context 的包装类,ContextImpl 才是 Context 的真正实现类,ContextWrapper 的核心工作都是交给其成员变量 mBase 来完成,mBase 是通过 attachBaseContext() 方法来设置的,本质上是 ContextImpl 对象。
ContextThemeWrapper 包含与主题相关的资源,所以 Activity 会继承它,而 Application、Service 不需要主题则没有继承它。
常见问题汇总
-
getApplication、getApplicationContext 区别
在绝大多数场景下,getApplication 和 getApplicationContext 这两个方法完全一致,返回值也相同。区别在于 getApplication 只存在于 Activity 和 Service 对象,对于 BroadcastReceiver 和 ContentProvider 只能使用 getApplicationContext。
但是对于 ContextProvider 使用 getApplicationContext 可能会出现空指针问题。当同一个进程有多个 apk 的情况下,对于第二个 apk 是由 provide 方式拉起的,provide 创建过程并不会初始化所在 application,此时返回的结果是 null。