你真的弄明白Context了嗎帜篇?

Context類,應(yīng)用程序環(huán)境的信息(即上下文诫咱,環(huán)境)笙隙,是一個(gè)抽象類。

public abstract class Context {}

通讀該類后發(fā)現(xiàn)幾乎都是我們平時(shí)需要用context調(diào)用的抽象方法坎缭,比如getResources()竟痰,getPackageManager(),getContentResolver()掏呼,getApplicationContext()坏快,obtainStyledAttributes(),getSharedPreferences(),startActivity(),checkPermission(),各種服務(wù)類型的聲明的靜態(tài)常量等等憎夷。還有調(diào)用Toast莽鸿、Dialog需要傳入。那么誰(shuí)來實(shí)現(xiàn)這個(gè)功能的呢拾给,既然上面Context是一個(gè)抽象類祥得,那么肯定有他的實(shí)現(xiàn)類。

ContextImpl蒋得,Context所有抽象功能的實(shí)現(xiàn)類:

class ContextImpl extends Context {
    private Context mOuterContext;
    ......
}

Context的繼承類ContextWrapper部分代碼级及,代理Context的實(shí)現(xiàn):

/**
 * Proxying implementation of Context that simply delegates all of its calls to
 * another Context.  Can be subclassed to modify behavior without changing
 * the original Context.
 */
public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
}

ContextThemeWrapper類代碼:

/**
 * A context wrapper that allows you to modify or replace the theme of the
 * wrapped context.
 */
public class ContextThemeWrapper extends ContextWrapper {
    private int mThemeResource;
    private Resources.Theme mTheme;
    private LayoutInflater mInflater;
    private Configuration mOverrideConfiguration;
    private Resources mResources;

ContextThemeWrapper有setTheme()方法:

    @Override
    public void setTheme(int resid) {
        if (mThemeResource != resid) {
            mThemeResource = resid;
            initializeTheme();
        }
}

Activity類代碼,因?yàn)锳ctivity帶窗口额衙,需要設(shè)置主題饮焦,所以需繼承于ContextThemeWrapper:

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {
    private static final String TAG = "Activity";
    private static final boolean DEBUG_LIFECYCLE = false;

    /** Standard activity result: operation canceled. */
    public static final int RESULT_CANCELED    = 0;
    /** Standard activity result: operation succeeded. */
    public static final int RESULT_OK           = -1;
    /** Start of user-defined activity results. */
public static final int RESULT_FIRST_USER   = 1;
}

Activity也復(fù)寫該方法并最終給window設(shè)置主題

    @Override
    public void setTheme(int resid) {
        super.setTheme(resid);
        mWindow.setTheme(resid);
    }

Application類代碼:

public class Application extends ContextWrapper implements ComponentCallbacks2 {
    private ArrayList<ComponentCallbacks> mComponentCallbacks =
            new ArrayList<ComponentCallbacks>();
    private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
            new ArrayList<ActivityLifecycleCallbacks>();
    private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;

    /** @hide */
    public LoadedApk mLoadedApk;

    public interface ActivityLifecycleCallbacks {
        void onActivityCreated(Activity activity, Bundle savedInstanceState);
        void onActivityStarted(Activity activity);
        void onActivityResumed(Activity activity);
        void onActivityPaused(Activity activity);
        void onActivityStopped(Activity activity);
        void onActivitySaveInstanceState(Activity activity, Bundle outState);
        void onActivityDestroyed(Activity activity);
  }
}

Service類代碼:

public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
private static final String TAG = "Service";
…
}

繼承關(guān)系圖:


image.png

表述為:
ContextImpl和ContextWrapper繼承自Context怕吴,ContextThemeWrapper、Application和Service繼承自ContextWrapper县踢,Activity繼承自ContextThemeWrapper转绷。ContextWrapper和ContextThemeWrapper都是Context的包裝類,它們都含有Context類型的mBase對(duì)象殿雪,mBase具體指向的是ContextImpl暇咆,這樣通過ContextWrapper和ContextThemeWrapper也可以使用Context的方法。ContextThemeWrapper中包含setTheme()和getTheme()等一些列主題相關(guān)的方法丙曙,所以需要設(shè)置主題的Activity需繼承ContextThemeWrapper爸业,讓mWindow.setTheme(),而不需要主題的Service則繼承ContextWrapper亏镰。

那么問題又來了
  • 一個(gè)應(yīng)用有多少個(gè)Context扯旷?

Application、Activity索抓、Service都間接繼承與Context钧忽,一個(gè)應(yīng)用有且只有一個(gè)Application對(duì)象,那么一個(gè)應(yīng)用Context總數(shù)為:

Context 數(shù) = Application 數(shù)(1) + Activity 數(shù)(Activity以及所有子類) + Service 數(shù)(Service以及所有子類);

  • 引用是該使用getApplicationcontext還是用Activity才不會(huì)引起內(nèi)存泄漏逼肯?

當(dāng)一個(gè)Context銷毀的時(shí)候耸黑,卻因?yàn)楸灰脤?dǎo)致銷毀失敗,導(dǎo)致內(nèi)存泄露篮幢。如一個(gè)單例模式的Manager類需要傳入一個(gè)Context大刊,而這個(gè)Manager的對(duì)象又需要在Activity中使用,如果我們傳遞Activity的Context就可能造成內(nèi)存泄漏三椿,Application的Context對(duì)象是隨著進(jìn)程存在的缺菌,所以應(yīng)該傳遞Application的Context。所以最終注意:盡量不要讓生命周期長(zhǎng)于Activity的對(duì)象引用Activity搜锰。

  • getApplication()與getApplicationContext()的愛恨情仇

getApplication()方法屬于Activity和Service伴郁,獲取到的是Activity中的mApplication對(duì)象;getApplicationContext()方法屬于ContextWrapper蛋叼,獲取到的是ContextWrapper中的Context類對(duì)象mBase焊傅。
在Activity和Service中可調(diào)用getApplication()獲取context,而其他以外的組件獲取context就只能調(diào)用getApplicationContext()鸦列。

來自Activity:

    /** Return the application that owns this activity. */
    public final Application getApplication() {
        return mApplication;
    }

來自ContextWrapper:

    @Override
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }

打印它們的內(nèi)存地址發(fā)現(xiàn)是相同的租冠,所以getApplication()和getApplicationContext()獲取到的是同一對(duì)象。

        Application mApplication = getApplication();
        Context mBase = getApplicationContext();

        Log.e("TAG","application " + mApplication);
        Log.e("TAG","context " + mBase);
image.png

關(guān)于Context的總結(jié)就到這里了薯嗤,該篇文章會(huì)不斷更新不斷擴(kuò)充詳細(xì)顽爹,對(duì)Context有個(gè)更完整認(rèn)識(shí)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末骆姐,一起剝皮案震驚了整個(gè)濱河市镜粤,隨后出現(xiàn)的幾起案子捏题,更是在濱河造成了極大的恐慌,老刑警劉巖肉渴,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件公荧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡同规,警方通過查閱死者的電腦和手機(jī)循狰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來券勺,“玉大人绪钥,你說我怎么就攤上這事」亓叮” “怎么了程腹?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)儒拂。 經(jīng)常有香客問我寸潦,道長(zhǎng),這世上最難降的妖魔是什么社痛? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任见转,我火速辦了婚禮,結(jié)果婚禮上蒜哀,老公的妹妹穿的比我還像新娘池户。我一直安慰自己,他們只是感情好凡怎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赊抖,像睡著了一般统倒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上氛雪,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天房匆,我揣著相機(jī)與錄音,去河邊找鬼报亩。 笑死浴鸿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弦追。 我是一名探鬼主播岳链,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼劲件!你這毒婦竟也來了掸哑?” 一聲冷哼從身側(cè)響起约急,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苗分,沒想到半個(gè)月后厌蔽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摔癣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年奴饮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片择浊。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡戴卜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出近她,到底是詐尸還是另有隱情叉瘩,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布粘捎,位于F島的核電站薇缅,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏攒磨。R本人自食惡果不足惜泳桦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望娩缰。 院中可真熱鬧灸撰,春花似錦、人聲如沸拼坎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泰鸡。三九已至债蓝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盛龄,已是汗流浹背饰迹。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留余舶,地道東北人啊鸭。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像匿值,于是被迫代替她去往敵國(guó)和親赠制。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容