Context相關(guān)

原文鏈接:
http://www.reibang.com/p/979bc7eaa43b?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=weixin#rd

前言

Context對象在我們的項(xiàng)目中實(shí)在是太常見了账千。啟動(dòng)Activity威恼、Service传蹈、發(fā)送一個(gè)Broadcast央拖,作為獲取各種系統(tǒng)Resources的參數(shù),Layout Inflation的參數(shù)垮卓,show a Dialog的參數(shù)等等垫桂,Context的使用不當(dāng),是可能造成內(nèi)存泄漏的粟按,當(dāng)你的工程代碼已經(jīng)達(dá)到十幾萬行甚至幾十萬行時(shí)诬滩,Context對象就對內(nèi)存泄漏造成非常可觀的影響了灭将,所以我們應(yīng)該對Context對象的使用疼鸟,做到心中有數(shù)

什么是Context

  • Context是為一個(gè)Android程序提供各種功能、資源庙曙、服務(wù)的一個(gè)環(huán)境空镜,Context的資源系統(tǒng)中只有一套,因?yàn)樗淖宇悾ˋpplication捌朴,Activity吴攒,Service)對這同一塊資源處理方式的不同,讓Context對象在功能上表現(xiàn)出各自之間的差異

Context對象之間的差異

重寫Context

public class LauncherApplication extends Application {

    private static Context context;

    @Override
    public void onCreate() {
        // 獲取Application中的Context
        context = getApplicationContext();
    }

    /**
     * 獲得Application的Context
     *
     * @return Context
     */
    public static Context getContext() {
        return context;
    }
}

清單文件配置

<application
    android:name=".LauncherApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
  • 配置完 android:name這個(gè)屬性砂蔽,以后應(yīng)用使用的就是你自定義的Application

在界面中show a Dialog

public class MainActivity extends Activity {

    private Context application;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        application = LauncherApplication.getContext();
    }

    public void ShowDialog (View view) {
        AlertDialog.Builder builder = new AlertDialog.Builder(application);
        builder.setTitle("ContextDemo");
        builder.setMessage("Context參數(shù)為applicationContext");
        builder.create();
        builder.show();
    }
}
  • 點(diǎn)擊后閃退閃退信息

       04-21 04:43:21.590 2104-2104/? E/AndroidRuntime: FATAL EXCEPTION: main
       Process: com.cat14.demo, PID: 2104
       java.lang.IllegalStateException: Could not execute method of the activity
           at android.view.View$1.onClick(View.java:3823)
           at android.view.View.performClick(View.java:4438)
           at android.view.View$PerformClick.run(View.java:18422)
           at android.os.Handler.handleCallback(Handler.java:733)
           at android.os.Handler.dispatchMessage(Handler.java:95)
           at android.os.Looper.loop(Looper.java:136)
           at android.app.ActivityThread.main(ActivityThread.java:5017)
           at java.lang.reflect.Method.invokeNative(Native Method)
           at java.lang.reflect.Method.invoke(Method.java:515)
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
           at dalvik.system.NativeStart.main(Native Method)
        Caused by: java.lang.reflect.InvocationTargetException
           at java.lang.reflect.Method.invokeNative(Native Method)
           at java.lang.reflect.Method.invoke(Method.java:515)
           at android.view.View$1.onClick(View.java:3818)
           at android.view.View.performClick(View.java:4438) 
           at android.view.View$PerformClick.run(View.java:18422) 
           at android.os.Handler.handleCallback(Handler.java:733) 
           at android.os.Handler.dispatchMessage(Handler.java:95) 
           at android.os.Looper.loop(Looper.java:136) 
           at android.app.ActivityThread.main(ActivityThread.java:5017) 
           at java.lang.reflect.Method.invokeNative(Native Method) 
           at java.lang.reflect.Method.invoke(Method.java:515) 
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
           at dalvik.system.NativeStart.main(Native Method) 
           
        Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
           at android.view.ViewRootImpl.setView(ViewRootImpl.java:540)
           at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:259)
           at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
           at android.app.Dialog.show(Dialog.java:286)
           at android.app.AlertDialog$Builder.show(AlertDialog.java:951)
           at com.cat14.demo.MainActivity.ShowDialog(MainActivity.java:26)
           at java.lang.reflect.Method.invokeNative(Native Method) 
           at java.lang.reflect.Method.invoke(Method.java:515) 
           at android.view.View$1.onClick(View.java:3818) 
           at android.view.View.performClick(View.java:4438) 
           at android.view.View$PerformClick.run(View.java:18422) 
           at android.os.Handler.handleCallback(Handler.java:733) 
           at android.os.Handler.dispatchMessage(Handler.java:95) 
           at android.os.Looper.loop(Looper.java:136) 
           at android.app.ActivityThread.main(ActivityThread.java:5017) 
           at java.lang.reflect.Method.invokeNative(Native Method) 
           at java.lang.reflect.Method.invoke(Method.java:515) 
           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
    

lvik.system.NativeStart.main(thod)

  • 可見洼怔,當(dāng)使用Application的Context時(shí),是無法彈出一個(gè)Dialog的左驾,因?yàn)镈ialog作為一個(gè)View镣隶,依附在Activity上,并且與Theme相關(guān)诡右,當(dāng)傳入?yún)?shù)為Activity的Context時(shí)矾缓,崩潰就解決了
  • Context對象之間的使用上的差異



Context相關(guān)的內(nèi)存泄漏問題

錯(cuò)誤的單例模式

public class Singleton {
    private static Single instance;
    private Context context;
    
    private Singleton(Context context) {
        this.mContext = context;
    }
    
    public static Singleton getInstance(Context context) {
        if (instance == null) {
            instance = new Singleton(mContext.getApplicationContext());
        }
        return instance;
    }
}
  • 這是一個(gè)非線程安全的單例模式
  • Activity A去getInstance獲得instance對象,傳入this
  • 常駐內(nèi)存的Singleton保存了你傳入的Activity A對象稻爬,并一直持有
  • 即時(shí)Activity被銷毀掉,但因?yàn)樗囊眠€存在于一個(gè)Singleton中蜕依,就不可能被GC掉桅锄,這樣就導(dǎo)致了內(nèi)存泄漏

View持有Activity引用

public class MainActivity extends Activity {
    private static Drawable mDrawable;
    
    @Override
    protected void onCreate(Bundle saveInstanceState) {
        super.onCreate(saveInstanceState);
        setContentView(R.layout.activity_main);
        ImageView iv = new ImageView(this);
        mDrawable = getResources().getDrawable(R.drawable.ic_launcher);
        iv.setImageDrawable(mDrawable);
    }
}
  • 有一個(gè)靜態(tài)的Drawable對象
  • 當(dāng)ImageView設(shè)置這個(gè)Drawable時(shí),ImageView保存了mDrawable的引用
  • 而ImageView傳入的this样眠,是MainActivity的mContext
  • 因?yàn)楸籹tatic修飾的mDrawable是常駐內(nèi)存的友瘤,MainActivity是它的間接引用
  • MainActivity被銷毀時(shí),也不能被GC掉檐束,所以造成內(nèi)存泄漏

正確使用Context

  • 一般Context造成的內(nèi)存泄漏辫秧,幾乎都是當(dāng)Context銷毀的時(shí)候,卻因?yàn)楸灰脤?dǎo)致銷毀失敗
  • 而Application的Context對象可以理解為隨著進(jìn)程存在的被丧,所以當(dāng)Application的Context能搞定的情況下盟戏,并且生命周期長的對象绪妹,優(yōu)先使用Application的Context
  • 內(nèi)存檢測的自動(dòng)化工具,LeakCanary
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柿究,一起剝皮案震驚了整個(gè)濱河市邮旷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝇摸,老刑警劉巖婶肩,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異貌夕,居然都是意外死亡律歼,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門啡专,熙熙樓的掌柜王于貴愁眉苦臉地迎上來险毁,“玉大人,你說我怎么就攤上這事植旧∪杞遥” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵病附,是天一觀的道長问窃。 經(jīng)常有香客問我,道長完沪,這世上最難降的妖魔是什么域庇? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮覆积,結(jié)果婚禮上听皿,老公的妹妹穿的比我還像新娘。我一直安慰自己宽档,他們只是感情好尉姨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吗冤,像睡著了一般又厉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上椎瘟,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天覆致,我揣著相機(jī)與錄音,去河邊找鬼肺蔚。 笑死煌妈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播璧诵,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼汰蜘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腮猖?” 一聲冷哼從身側(cè)響起鉴扫,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎澈缺,沒想到半個(gè)月后坪创,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姐赡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年莱预,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片项滑。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡依沮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出枪狂,到底是詐尸還是另有隱情危喉,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布州疾,位于F島的核電站辜限,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏严蓖。R本人自食惡果不足惜薄嫡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颗胡。 院中可真熱鬧毫深,春花似錦、人聲如沸毒姨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弧呐。三九已至鸳址,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泉懦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工疹瘦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留崩哩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像邓嘹,于是被迫代替她去往敵國和親酣栈。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

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