遇到这么个问题:
两个应用以相同的方式new一个控件,但是显示的样式却不一样,最后追溯代码,最终定位到原来传入的context不一样,一个为Activity的,另一个是Application的。
一、Context是什么?
语境、上下文,即环境的信息或者场景,它的实现是由Android系统提供的,访问app的资源,启动activity,获取系统服务,创建View等都会牵扯到Context。
二、Context创建
1、创建Application时会创建一个ApplicationContext,生命周期跟随应用走,当Application被摧毁时Context才被摧毁。
2、创建Activity时会创建一个Activity的Context,生命周期跟随Activity。
3、创建Service时创建Service的Context,生命周期跟随Service。
Context的总数 = Activity(个数)+Service(个数)+1个Application的Context。
三、获取Context
1、getContext();
2、getBaseContext();
3、getApplicationContext();
4、this;
四种方法获取的Context如下:
通过View.getContext()和Activity.this其实时相同的,getBaseContext获取到的是ContextImpl的,getApplicationContext获取的是Application的。
四、通过Context获取资源
最常见的方法就是getContext().getResource(),通过这个方法可以获取String,Drawable等资源。 还有自定义View的时候也常用到context.obtainStyledAttributes()这个方法。
由上面第三点getContext的不同可以知道如果在应用里通过obtainStyledAttributes获取资源,使用getContext()和getApplicationContext() 是不一样的。
例如应用在Manifest里设置了App的Theme,通过getApplicationContext().getTheme是可以取得应用的Theme;但是通过Activity的context.getTheme是获取不到的。
会有部分人误认为只要设置了Application的Theme,Activity里getTheme就是正确的,我就是那个人。以下是Context的部分类图:
可以很明显地看到Activity是继承ContextThemeWrapper,而Application是继承ContextWrapper的,ContextThemeWrapper里重写了setTheme方法。
如果使用getContext获取资源,取决于Context是属于哪一个。
一个简单的例子:
Manifest设置了如下样式:
使用两个不同的Context创建EditText,其对应的样式也不一样:
ActivityContext的EditText可以有主题定制的颜色,而getApplication的则没有,因为在EditText的初始化时使用的是context.obtainStyledAttributes 这个方法,而这个方法调用的是getTheme().obtainStyledAttributes,由上面可以知道context的不同,getTheme也是不同的,所以出现这样的问题。
public final TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
return getTheme().obtainStyledAttributes(attrs);
}
这种小问题,稍不注意有时候也是个大麻烦。