Context是我們?cè)诰帉慉ndroid程序經(jīng)常使用到的對(duì)象,意思為上下文對(duì)象。 常用的有Activity的Context還是有Application的Context。Activity用來展示活動(dòng)界面,包含了很多的視圖,而視圖又含有圖片,文字等資源。在Android中內(nèi)存泄露很容易出現(xiàn),而持有很多對(duì)象內(nèi)存占用的Activity更加容易出現(xiàn)內(nèi)存泄露,開發(fā)者需要特別注意這個(gè)問題。
本文講介紹Android中Context,更具體的說是Activity內(nèi)存泄露的情況,以及如何避免Activity內(nèi)存泄露,加速應(yīng)用性能。
Drawable引起的內(nèi)存泄露
Drawable引起內(nèi)存泄露這個(gè)問題是比較隱晦,難以察覺的。在閱讀了Romain Guy的Avoiding memory leaks,結(jié)合grepcode查看源碼才明白了。
在Android系統(tǒng)中,當(dāng)我們進(jìn)行了屏幕旋轉(zhuǎn),默認(rèn)情況下,會(huì)銷毀掉當(dāng)前的Activity,并創(chuàng)建一個(gè)新的Activity并保持之前的狀態(tài)。在這個(gè)過程中,Android系統(tǒng)會(huì)重新加載程序的UI視圖和資源。假設(shè)我們有一個(gè)程序用到了一個(gè)很大的Bitmap圖像,我們不想每次屏幕旋轉(zhuǎn)時(shí)都重新加載這個(gè)Bitmap對(duì)象,最簡(jiǎn)單的辦法就是將這個(gè)Bitmap對(duì)象使用static修飾。
private static Drawable sBackground;@Overrideprotected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); if (sBackground == null) { sBackground = getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground); setContentView(label);}但是上面的方法在屏幕旋轉(zhuǎn)時(shí)有可能引起內(nèi)存泄露,無論是咋一看還是仔細(xì)看這段代碼,都很難發(fā)現(xiàn)哪里引起了內(nèi)存泄露。
當(dāng)一個(gè)Drawable綁定到了View上,實(shí)際上這個(gè)View對(duì)象就會(huì)成為這個(gè)Drawable的一個(gè)callback成員變量,上面的例子中靜態(tài)的sBackground持有TextView對(duì)象lable的引用,而lable只有Activity的引用,而Activity會(huì)持有其他更多對(duì)象的引用。sBackground生命周期要長(zhǎng)于Activity。當(dāng)屏幕旋轉(zhuǎn)時(shí),Activity無法被銷毀,這樣就產(chǎn)生了內(nèi)存泄露問題。
2.3.7及以下版本Drawable的setCallback方法的實(shí)現(xiàn)
public final void setCallback(Callback cb) { mCallback = cb;}好在從4.0.1開始,引入了弱引用處理這個(gè)問題,弱引用在GC回收時(shí),不會(huì)阻止GC回收其指向的對(duì)象,避免了內(nèi)存泄露問題。
public final void setCallback(Callback cb) { mCallback = new WeakReference<Callback>(cb);}單例引起的內(nèi)存泄露
單例是我們比較簡(jiǎn)單常用的一種設(shè)計(jì)模式,然而如果單例使用不當(dāng)也會(huì)導(dǎo)致內(nèi)存泄露。 比如這樣一個(gè)例子,我們使用餓漢式初始化單例,AppSettings我們需要持有一個(gè)Context作為成員變量,如果我們按照下面的實(shí)現(xiàn)其實(shí)是有問題。
public class AppSettings { private Context mAppContext; private static AppSettings sInstance = new AppSettings(); //some other codes public static AppSettings getInstance() { return sInstance; } public final void setup(Context context) { mAppContext = context; }}sInstance作為靜態(tài)對(duì)象,其生命周期要長(zhǎng)于普通的對(duì)象,其中也包含Activity,當(dāng)我們進(jìn)行屏幕旋轉(zhuǎn),默認(rèn)情況下,系統(tǒng)會(huì)銷毀當(dāng)前Activity,然后當(dāng)前的Activity被一個(gè)單例持有,導(dǎo)致垃圾回收器無法進(jìn)行回收,進(jìn)而產(chǎn)生了內(nèi)存泄露。
解決的方法就是不持有Activity的引用,而是持有Application的Context引用。代碼如下修改
public final void setup(Context context) { mAppContext = context.getApplicationContext(); }訪問這里了解更多關(guān)于單例模式的問題
條條方法返回Context
通常我們想要獲取Context對(duì)象,主要有以下四種方法
其他內(nèi)存泄露問題
OnSharedPreferenceChangeListener詳解及出現(xiàn)不觸發(fā)解決辦法
避免內(nèi)存泄露須謹(jǐn)記
參考文章
Avoiding memory leaks
Difference between getContext() , getApplicationContext() , getBaseContext() and “this”
Android
主站蜘蛛池模板:
鄂伦春自治旗|
新乡市|
城固县|
思茅市|
永昌县|
昌都县|
英山县|
民丰县|
山丹县|
神木县|
察雅县|
基隆市|
襄垣县|
江西省|
桂林市|
固安县|
铜陵市|
阿城市|
登封市|
贞丰县|
屏东县|
新乐市|
莎车县|
沈丘县|
谷城县|
黑山县|
拉萨市|
昌乐县|
山东省|
大新县|
温宿县|
疏勒县|
玛纳斯县|
上林县|
文昌市|
莱西市|
甘肃省|
六安市|
馆陶县|
犍为县|
碌曲县|