HI,Context!

作者: Mr_高 | 来源:发表于2016-01-07 17:19 被阅读260次

    Context的理解

    context的使用场景:

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

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

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

    首先来一张Context的家族谱

    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!

        本文链接:https://www.haomeiwen.com/subject/inefkttx.html