今天我们来聊聊Context那些事儿。
首先,Context是个啥?
字面意思上,很容易理解:上下文。
再具体一点,看下sdk中对它的描述:
Interface to global information about an application environment 应用环境的整体信息的接口。
这它喵的一点用处都没有啊!
所以我们来看一下这货的源码:
public abstract class Context {
/** Return an AssetManager instance for your application's package. */
public abstract AssetManager getAssets();
/** Return a Resources instance for your application's package. */
public abstract Resources getResources();
/** Return PackageManager instance to find global package information. */
public abstract PackageManager getPackageManager();
/** Return a ContentResolver instance for your application's package. */
public abstract ContentResolver getContentResolver();
public abstract Looper getMainLooper();
public abstract Context getApplicationContext();
}
看到第一行我就给跪了,这货居然还是个抽象类,再仔细看下里面的方法,getResources(),getPackageManager()等等,咦?是不是有点眼熟啊,这些方法在哪里见过。
是的,Activity里面就有这些方法。
所以你应该猜到了:Activity是Context的一个子类
来看下Activity的源码:
public class Activity extends ContextThemeWrapper
而ContextThemeWrapper:
public class ContextThemeWrapper extends ContextWrapper
最后,ContextWrapper继承自Context:
public class ContextWrapper extends Context
这就是为啥,我们通常会在Activity里这么写:
public class MainActivity extends Activity {
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
...
}
然而你以为到这儿就结束了吗?当然不是,如果是的话我就不会写这篇博客了。。。
我们再看一下Application的源码:
public class Application extends ContextWrapper
还有Service的源码:
public abstract class Service extends ContextWrapper
所以。。。Application和Service也是Context的子类。
这意味着什么?这意味着我们可以这么写:
public class DemoApplication extends Application {
private Context mContext;
@Override
public void onCreate() {
super.onCreate(savedInstanceState);
mContext = this;
...
}
以及这么写:
public class DemoService extends Service {
private Context mContext;
@Override
public void onCreate() {
super.onCreate(savedInstanceState);
mContext = this;
...
}
我估计这时候你已经懵逼了。。。
现在我们有3个Context了,这看起来是个好事儿,因为貌似我们的选择多了,但是也是个坏事儿,因为你不知道啥时候该用哪个了。
我们再来举个例子,写一个UserManager的类,并把它设置成单例(通常我们并不想要多个Manager的实例同时存在),因为这个类要用到SharedPreferences,所以我们需要一个Context:
public class UserManager {
private static Context mContext;
private static UserManager instance = new UserManager();
private UserManager() {
}
public static UserManager getInstance(Context context) {
mContext = context;
return instance;
}
看起来有问题吗?
你知道传进来的这个Context,究竟是哪种吗?Activity? Service?还是Application?
有童鞋可能会说了,管这个干啥,给啥用啥呗。
但是我们仔细想下,如果这个是Activity的Context,那是不是意味着,这个Activity是不能被释放掉的,因为我们有地方在使用Activity的引用,而使用这个引用的地方是全局的单例,它的生命周期,是整个app的生命周期。然后顺带着,因为Activity没有释放掉,所以Activity里面的各种view,各种变量都不会被释放掉。
如果我们的代码里充斥着这种引用,那你会有很多个Activity无法释放掉,结果是什么呢,你的app需要占用大量的内存,或者内存溢出,crash了。
那Context还就不能用了???
当然不是。你可以用Application的Context。
因为Application本身就是单例的,而且它的生命周期,跟app的生命周期是一致的:
public class UserManager {
private static Context mContext;
private static UserManager instance = new UserManager();
private UserManager() {
}
public static UserManager getInstance(Context context) {
mContext = context.getApplicationContext();
return instance;
}
好了,之所以指出上面的这个例子,我是想告诉大家,三种Context是有区别的。
- 你可以在Activity里,用Context去show一个dialog,但是Application和Service不行
- 你可以在Activity里,使用LayoutInflater,但是Application和Service不行(或者说,没有意义)
所以归结起来:
- 所有对UI的操作,我们都需要使用Activity的Context
- 绝大多数情况下,自己用自己的的Context
- 当你需要保存某个Context的引用时,把它转换成Application的Context