Context的理解
context的使用场景:
- getResources()
- StartActivity()
- 弹出dialog
- inflate布局文件
- 。。。。。
总之context贯穿了我们安卓整个开发,自然也就尤为重要。但是,我们是否真的完全理解了Context了呢?其实不然,下面跟我一起看如下几个问题。
- getBaseContext和getApplication,getApplicationContext的区别?
- 分别在什么时候我们可以使用getBaseContext和getApplication,getApplicationContext呢?
首先来一张Context的家族谱
下面从Context开始分析
Context,作为整个家族的族长,分量自然是最大的,查看源码的得知Context是一个抽象类。仔细想想这是必须的嘛,根据面向对象的编程思想,组长必须是定义族规的,而并非要事必躬亲的,果然,一群抽象方法袭来。。。
//省略大量代码
public abstract AssetManager getAssets();
public abstract Resources getResources();
//省略大量代码
public abstract PackageManager getPackageManager();
public abstract ContentResolver getContentResolver();
public abstract Looper getMainLooper();
public abstract Context getApplicationContext();
//省略大量代码
呵呵,就问你怕不怕。。
根据这些,我们可以得出结论,context就是定义规则的一个族长,这些规则包括获取资源文件的内容,获取looper,获取PackageManager,当然还有getApplicationContext这个重要的方法了。
getApplicationContext存在在Context中代表什么?代表Activiy,Serviec,Application ,中都可以调用啊,有木有!!!!也就是说getApplicationContext的作用域是最广的了。然而我们却没有看到getBaseContext和getApplication。果断不开心啊!没事,继续往下看!
Contextimpl来了,一看这个名就知道他是context的具体实现了,小样起名也不知道矜持点。。哈哈我们来看一下他的内容,不看不知道啊,这小伙子地道啊,族长的要求都实现了有木有,这里只举与本文相关的getApplicationContext()方法,接好源码
@Override
public Context getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInfo.getApplication() : mMainThread.getApplication();
}
看完代码mPackageInfo.getApplication() mMainThread.getApplication();我们分别看源码的实现,这两个方法都会返回一个Application对象,那么返回究竟是那个Application呢?拜托,安卓中一个程序只有一个Application好不好!!!所以我们就可以初步认为getApplicationContext获得的是application对象,而且在安卓中一个程序中只有一个Application对象,嗯get!(如果你想说,都到这了,为什么不看看怎么获取到的applicaion呢,满足你的好奇心),想知道application怎么创建出来的
那只能代码追踪大法。。。
以上那两个途径最后都能追踪到LoadedApk.java文件中(ContextImpl作为context)
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
好嘛!先搞一个ContextImpl对象,然后利用mInstrumentation来new一个Application,并且把ContextImpl对象传进去。在Instrumentation中(ContextImpl作为context)
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
好吧,原来Application是反射出来的,有兴趣的同学可以看看activity,其实它也是反射出来的。那么 app.attach(context)是什么?点进方法,
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
再点击attachBaseContext,嗯,跳到了ContextWrapper,把ContextImpl传到了ContextWrapper
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
再看ContextWrapper
一看名称,嗯,包装类,再一看源码
public Context getBaseContext() {
return mBase;
}
@Override
public AssetManager getAssets() {
return mBase.getAssets();
}
@Override
public Resources getResources()
{
return mBase.getResources();
}
@Override
public PackageManager getPackageManager() {
return mBase.getPackageManager();
}
全是mBase.getXXX,mBase是什么,其实mBase就是刚才传进来的ContextImpl有木有!!,妈蛋,这孙子什么都没干就是调用ContextImpl的方法,哎,不对,我们期待的getBaseContext方法出现了,什么,返回的还是mBase。。。。
最终我们得出结论
public Context getBaseContext() {
return mBase;
}
返回的就是一个new出来的ContextImpl
最后还有getapplication了,既然还没出现就接着往下找
看ContextThemeWrapper嗯,theme主题,带主题的ContextWrapper,activity是需要界面的,这个名字好有道理!ctrl+f,没找到,不管继续向下,然后终于到activity,看到这个类就兴奋,,毕竟helloworld就是从它开始的,好吧ctrl+f,终于搜到了getapplication看方法
public final Application getApplication() {
return mApplication;
}
跟想象的一样就是返回一个Application,当然也是,毕竟方法名就是getApplication,难不成还能返回一个textview???
再看Service中,
public final Application getApplication() {
return mApplication;
}
同样是这样。。。
到此,我们达到了我们的目的,找到了getApplicationContext,getApplication,getBaseContext的出处,既然都看完了我们就来回顾一下吧
- getApplicationContext和getApplication返回结果一样,只是两者作用域不一样,getApplicationContext在所有context子类中都可以使用,getApplication只能在activity,或者service中使用(其实这也满足了大部分要求了)
- getBaseContext返回的是一个Contextimpl对象
- 有些布局必须依附在一个父布局中,这时context必须为activity类型的,当然你倔强的用application类型的也不会报错,可能样式加载不出来,毕竟activity是继承ContextThemeWrapper的
另外,抛出一个问题,application和contextimol的区别是什么??
以上就是主要内容了,欢迎大家订正