总结:
生命周期跟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 |
|
Context是个抽象类,里面定义了各种抽象方法,包括获取系统资源,获取系统服务,发送广播,启动Activity、Service等,结合上图:Activity、Service、Application都是继承自ContextWrapper(上下文功能的封装类),而在ContextWrapper内部会包含一个名为 mBase 的 Context 对象,由这个 mBase 对象去实现了绝大多数的方法:
-
/**
-
* Proxying implementation of Context that simply delegates all of its calls to
-
* another Context. Can be subclassed to modify behavior without changing
-
* the original Context.
-
*/
-
public class ContextWrapper extends Context {
-
Context mBase;
-
/**
-
* Set the base context for this ContextWrapper. All calls will then be
-
* delegated to the base context. Throws
-
* IllegalStateException if a base context has already been set.
-
*
-
* @param base The new base context for this wrapper.
-
*/
-
protected void attachBaseContext(Context base) {
-
if (mBase != null) {
-
throw new IllegalStateException("Base context already set");
-
}
-
mBase = base;
-
}
-
/**
-
* @return the base context as set by the constructor or setBaseContext
-
*/
-
public Context getBaseContext() {
-
return mBase;
-
}
-
@Override
-
public AssetManager getAssets() {
-
return mBase.getAssets();
-
}
-
@Override
-
public Resources getResources() {
-
return mBase.getResources();
-
}
-
@Override
-
public ContentResolver getContentResolver() {
-
return mBase.getContentResolver();
-
}
-
@Override
-
public Looper getMainLooper() {
-
return mBase.getMainLooper();
-
}
-
@Override
-
public Context getApplicationContext() {
-
return mBase.getApplicationContext();
-
}
-
@Override
-
public String getPackageName() {
-
return mBase.getPackageName();
-
}
-
@Override
-
public void startActivity(Intent intent) {
-
mBase.startActivity(intent);
-
}
-
@Override
-
public void sendBroadcast(Intent intent) {
-
mBase.sendBroadcast(intent);
-
}
-
@Override
-
public Intent registerReceiver(
-
BroadcastReceiver receiver, IntentFilter filter) {
-
return mBase.registerReceiver(receiver, filter);
-
}
-
@Override
-
public void unregisterReceiver(BroadcastReceiver receiver) {
-
mBase.unregisterReceiver(receiver);
-
}
-
@Override
-
public ComponentName startService(Intent service) {
-
return mBase.startService(service);
-
}
-
@Override
-
public boolean stopService(Intent name) {
-
return mBase.stopService(name);
-
}
-
@Override
-
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
-
return mBase.bindService(service, conn, flags);
-
}
-
@Override
-
public void unbindService(ServiceConnection conn) {
-
mBase.unbindService(conn);
-
}
-
@Override
-
public Object getSystemService(String name) {
-
return mBase.getSystemService(name);
-
}
-
......
-
}
所以,我们在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中的空指针问题
先看下面两个例子:
-
//第一种使用方式
-
public class MyApplication extends Application {
-
public MyApplication() {
-
String packageName = getPackageName();
-
Log.d("TAG", "package name is " + packageName);
-
}
-
}
-
//第二种使用方式
-
public class MyApplication extends Application {
-
@Override
-
public void onCreate() {
-
super.onCreate();
-
String packageName = getPackageName();
-
Log.d("TAG", "package name is " + packageName);
-
}
-
}
运行结果:第一种使用方式有空指针错误,第二种则运行正常。为什么呢?ContextWrapper中有一个attachBaseContext()方法,只有这个方法会将传入的一个Context参数赋值给mBase对象,在mBase非空后,调用mBase方法才不会崩溃。
Application中方法的执行顺序如下图所示:
Application中在onCreate()方法里去初始化各种全局的变量数据是一种比较推荐的做法,但是如果你想把初始化的时间点提前到极致,也可以去重写attachBaseContext()方法,如下所示:
-
public class MyApplication extends Application {
-
@Override
-
protected void attachBaseContext(Context base) {
-
// 在这里调用Context的方法会空指针错误
-
super.attachBaseContext(base);
-
// 在这里可以正常调用Context的方法
-
}
-
}