这是四大组件的第一篇(其他还没整理好:) ),之前有个习惯,就是把一些笔记记在书上,但是随着书越来越多,翻阅的时候比较麻烦,尤其是一段时间不用之后,想要翻阅某个知识点太费劲,这里就打算统一整理在一起,方便查看。
其中有很多内容参照了网上的博文,但是时间比较久,忘记出处了。另外就是参照Android developer的相关文档,加上自己的理解,如果有错误,欢迎指出啊。
分类
Application的Context
Application对象以单例的形式出现,代表正在运行的APP,Application继承了ContextWrapper,所以可以认为它也是一个Context,此处将其称为“Application的Context”。
获取方式:
在Activity或Service中,可通过调用getApplication()函数获取。
可以通过context.getApplicationContext()获取。
Activity、Service的Context
Activity和Service同样都继承于ContextWrapper,所以也可以认为它们是Context。
BroadcastReceiver的Context
BroadcastReceiver本身不是Context,其内部也不含有Context,但在onReceive(Context context, Intent intent)中有context参数。这个context随着receiver的注册方式的不同而不同:
静态注册:context为ReceiverRestrictedContext,bindService和registerReceiver被禁用
动态注册:context为Activity的context
LocalBroadcastManager的动态注册: context为Application的context
ContentProvider的Context
ContentProvider本身不是Context,但可以通过getContext()获取一个context对象(该对象代表的是当前provider运行的context)。具体来讲:
如果provider和调用者在同一个process中,context就是Application的context
如果provider和调用者分属不同的进程,getContext将创建一个新的context代表此provider所运行的包。
getContext()必须在onCreate调用之后才可用,在构造器中调用将返回null。
能力
Application | Activity | Service | Content Provider | Broadcast Receiver(静态) | |
---|---|---|---|---|---|
显示对话框 | No | Yes | No | No | No |
启动Activity | No1 | Yes | No1 | No1 | No1 |
填充布局 | No2 | Yes | No2 | No2 | No2 |
启动Service | Yes | Yes | Yes | Yes | Yes |
绑定Service | Yes | Yes | Yes | Yes | No |
发送Broadcast | Yes | Yes | Yes | Yes | Yes |
注册Broadcast-Receiver | Yes | Yes | Yes | Yes | No3 |
加载资源值 | Yes | Yes | Yes | Yes | Yes |
注意:
- No1表示Application的Context确实可以启动一个Activity,但是它需要创建一个新的task,会造成APP中存在不标准的回退栈,不推荐。
- No2表示这是非法的,填充虽然可以完成,但使用的系统默认的theme,而非APP的theme。
- No3在4.2以上,如果receiver是null(用于粘性广播,已被标注为过时),是允许的。
综上:与UI相关的功能只能由Activity的Context去处理。
注意事项
当需要保存一个context的引用时,如果它超过了你的Activity或Service的生命周期(即便只是暂时的),需要保存Application的context。
比较典型的:单例。
错误的例子:
public class CustomManager{
private static CustomManager sInstance;
private Context mContext;
private CustomManager(Context context){
mContext = context;
}
public static CustomManager getInstance(Context context){
if( sInstance == null ){
sInstance = new CustomManager(context);
}
return sInstance;
}
}
原因:如果传入的context是一个Activity,则由于它在单例的实现中被引用,导致该Activity对象及其所引用的对象永远不能被垃圾回收,有内存泄漏的风险。
更好的实现:
public class CustomManager{
private static CustomManager sInstance;
private Context mContext;
private CustomManager(Context context){
mContext = context;
}
public static CustomManager getInstance(Context context){
if( sInstance == null ){
sInstance = new CustomManager(context.getApplicationContext());
}
return sInstance;
}
}
另一个比较典型的例子:在后台线程或一个等待的Handler中如果需要保存Context的引用,也请使用Application的context。