HI,Context!

Context的理解

context的使用场景:

  1. getResources()
  2. StartActivity()
  3. 弹出dialog
  4. inflate布局文件
  5. 。。。。。

总之context贯穿了我们安卓整个开发,自然也就尤为重要。但是,我们是否真的完全理解了Context了呢?其实不然,下面跟我一起看如下几个问题。

  • getBaseContext和getApplication,getApplicationContext的区别?
  • 分别在什么时候我们可以使用getBaseContext和getApplication,getApplicationContext呢?

首先来一张Context的家族谱

HI,Context!_第1张图片
context家族族谱.png

下面从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的区别是什么??

以上就是主要内容了,欢迎大家订正

你可能感兴趣的:(HI,Context!)