聊聊Android中的ContextImpl

說起這個ContextImpl.可能有些同學不太熟悉,但說起Context,我想都認識它吧,上下文,也可以說是代表一種所在的場景,由于Context只是一個抽象類,而抽象類必定是有一個具體的實現類的,另外還有ContextThemeWrapper和ContextWrapper,不過這些都是Context的子類而已,他們是以裝飾模式而存在的一種關系,簡單說下裝飾模式,裝飾模式是常用的設計模式之一,一般情況下如果需要動態(tài)地給一個對象添加一些額外的職責但又不想增加子類,那么就可以用到裝飾模式了,如果單純增加功能來說,Decorator模式相比生成子類更為靈活,該模式以對客 戶端透明的方式擴展對象的功能,下面舉一個簡單的例子說明一下,首先一個人,有吃飯的功能接口

代碼如下:

Component

 public interface Person {

    void eat();
}

ConcreteComponent

public class Man implements Person {

    public void eat() {
        System.out.println("男人在吃飯");
    }
}

Decorator(這個類是關鍵,實現了接口并且有真實對象的引用)

public abstract class Decorator implements Person {

    protected Person person;

    public Decorator(Person person){
        this.person=person;
    }

    public void eat() {
        person.eat();
    }
}

下面的就是具體的添加額外功能的了具體子類,比如有些人吃飯前先洗手或者吃完飯后洗碗之類,當然具體什么事情根據業(yè)務決定

public class ManDecoratorA extends Decorator {

    public ManDecoratorA(Person person) {
        super(person);
    }
    public void eat() {
        wash();
        super.eat();
    }

    private void wash() {
        System.out.println("飯前先洗洗手");
    }
}
public class ManDecoratorB extends Decorator {

    public ManDecoratorB(Person person) {
        super(person);
    }
    public void eat() {
        super.eat();
        washDishes();
    }

    private void washDishes(){
          System.out.println("吃完飯后洗碗");
    }
}

測試的結果為:

 public static void main(String[] args) {
        Person person=new Man();
        ManDecoratorA md1=new ManDecoratorA(person);
        ManDecoratorB md2=new ManDecoratorB(person);
        md1.eat();
        System.out.println("===============");
        md2.eat();
    }

運行結果為:

QQ圖片20171208164154.png

可以看到在吃飯前和吃飯后做了一些事情,這就達到了不增加子類而又可以添加一些額外功能的作用

回到ContextImpl和Context,其實也是一樣的,這個ContextImpl相當于代碼中的Man,而Context相當于Person,只是一個接口,一個抽象類,但本質都是一樣,而Decorator相當于ContextWrapper,那么具體的抽象實現類為什么呢,在Android中Activity和Service就是類似代碼中的ManDecoratorA和ManDecoratorB了,只不過Activity有界面,自然就有Theme主題,因此對應的是ContextThemeWrapper,現在已經對裝飾模式理解的更深了吧。

現在回到ContextImpl本身來,ContextImpl作為Context的抽象類,實現了所有的方法,我們常見的getResources(),getAssets(),getApplication()等等的具體實現都是在ContextImpl的,下面是具體的一些代碼

 @Override
    public ContentResolver getContentResolver() {
        return mContentResolver;
    }

    @Override
    public Looper getMainLooper() {
        return mMainThread.getLooper();
    }

    @Override
    public Context getApplicationContext() {
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }

可以看到我們平常開發(fā)所調用的方法的實現都是在這里完成,作為一名android開發(fā)者,我們應該多去研究一些源碼之類的,這樣在出問題的時候可以根據源碼找出問題的具體所在,ContextImpl在主線程ActivityThread通過傳入主線程對象創(chuàng)建了一個系統(tǒng)的ContextImpl,下面是代碼:

 public ContextImpl getSystemContext() {
        synchronized (this) {
            if (mSystemContext == null) {
                mSystemContext = ContextImpl.createSystemContext(this);
            }
            return mSystemContext;
        }
    }

這個是在ActivityThread里面完成的,ActivityThread是Android應用程序的主線程環(huán)境,關于對ActivityThread的分析,可以看我的另一篇文章 關于Android主線程(ActivityThread)源代碼分析以及一些特殊問題的非常規(guī)方法
大家有空可以去看看,實際上Activity和Service中的Context也是通過ContextImpl來的,大家有時間可以去看看主線程的源碼,好了,我們知道了ContextImpl里面的方法了,下面說一個具體的不太常見的需求.曾經有個需求,要求用戶在卸載之后再重新安裝進入的時候能夠讀取一些配置信息,當初服務端要求這個客戶端自己去實現,有同學說了這個本身不難,很簡單啊,用SharePreference就可以搞定,恩,是很簡單,可是需求說了再卸載之后重新進入的時候需要讀取出來原來的配置,卸載之后整個應用程序的目錄都不見了,所有數據都消失了,配置文件哪里來呢?,我們知道,SharePreference是保存在一個叫做shared_prefs目錄下面的,這個目錄隨著程序卸載也會被刪掉,也就是說卸載之后,保存在原來默認的存儲就會全部消失,那應該怎么辦呢,其實只需要修改原來的路徑改為自定義的路徑就好,比如放在外部SD卡或者其他地方,這樣程序卸載的時候就不會刪除這些自定義的目錄了,從而可以在安裝再次進入的時候讀取出來,看起來這個方法可以的

ContextImpl里面有一個字段mPreferencesDir,這個文件目錄就是保存了SharePreference路徑的,我們只需要修改這個為我們自定義的路徑就好了,由于ContextImpl是一個隱藏類,我們需要使用反射去實現,隨我走一波吧,下面是具體的代碼:

try {
            Class<?> clazz=Class.forName("android.app.ContextImpl");
            Method method=clazz.getDeclaredMethod("getImpl", Context.class);
            method.setAccessible(true);
            Object mContextImpl=method.invoke(null,this);
            //獲取ContextImpl的實例
            Log.d("[app]","mContextImpl="+mContextImpl);
            Field mPreferencesDir=clazz.getDeclaredField("mPreferencesDir");
            mPreferencesDir.setAccessible(true);
            //我們自定義的目錄假設在SD卡, 其他目錄也是一樣的
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                File file=new File(Environment.getExternalStorageDirectory(),"new_shared_pres");
                if (!file.exists()){
                    file.mkdirs();
                }
                mPreferencesDir.set(mContextImpl,file);
                Log.d("[app]","修改sp路徑成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    下面是具體的執(zhí)行結果:
    12-08 17:28:42.811 12404-12404/com.example.hotfixdemo D/[app]: mContextImpl=android.app.ContextImpl@db6fc37
12-08 17:28:42.818 12404-12404/com.example.hotfixdemo D/[app]: 修改sp路徑成功

OK,已經成功修改為自定義的路徑了,這樣就達到目的了。

實際上,除了SP的路徑,ContextImpl里面還有很多類似這樣的路徑,一樣是可以通過類似的手段修改的,達到一些特定的目的,比如360的插件框架也是Hook了ContextImpl類的數據庫路徑,達到加載的目的,大家有空可以去看看,Java層的Hook基本以反射和動態(tài)代理為主,這兩方面的內容,有時間再寫,今天就寫到這里,感謝大家閱讀。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容