日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android开发中,可能会导致内存泄露的问题

發(fā)布時間:2025/3/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android开发中,可能会导致内存泄露的问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
轉(zhuǎn)自 : http://spencer-dev.lofter.com/post/d7b9e_6faf120

在android編碼中,會有一些簡便的寫法和編碼習(xí)慣,會導(dǎo)致我們的代碼有很多內(nèi)存泄露的問題。在這里做一個已知錯誤的總結(jié)(其中有一些是個人總結(jié)和參考其他博主的文章,在此表示感謝)。
本文會不定時更新,將自己遇到的內(nèi)存泄漏相關(guān)的問題記錄下來并提供解決辦法。

1. 編寫單例的時候常出現(xiàn)的錯誤

錯誤方式:

public class Foo{private static Foo foo;private Context mContext;private Foo(Context mContext){this.mContext = mContext;}// 普通單例,非線程安全public static Foo getInstance(Context mContext){if(foo == null)foo = new Foo(mContext);return foo;}public void otherAction(){mContext.xxxx();......}}
錯誤原因:

如果我們在Activity A中或者其他地方使用Foo.getInstance()時,我們總是會順手寫一個『this』或者『mContext』(這個變量也是指向this)。 試想一下,當(dāng)前我們所用的Foo是單例,意味著被初始化后會一直存在與內(nèi)存中,以方便我們以后調(diào)用的時候不會在此次創(chuàng)建Foo對象。但Foo中的 『mContext』變量一直都會持有Activity A中的『Context』,導(dǎo)致Activity A即使執(zhí)行了onDestroy方法,也不能夠?qū)⒆约轰N毀。但『applicationContext』就不同了,它一直伴隨著我們應(yīng)用存在(中途也可能 會被銷毀,但也會自動reCreate),所以就不用擔(dān)心Foo中的『mContext』會持有某Activity的引用,讓其無法銷毀。

正確方式:

public class Foo{private static Foo foo;private Context mContext;private Foo(Context mContext){this.mContext = mContext;}// 普通單例,非線程安全public static Foo getInstance(Context mContext){if(foo == null)foo = new Foo(mContext.getApplicationContext());return foo;}public void otherAction(){mContext.xxxx();….}}
2. 使用匿名內(nèi)部類的時候經(jīng)常出現(xiàn)的錯誤

錯誤方式:

public class FooActivity extends Activity{private TextView textView; private Handler handler = new Handler(){@overridepublic void handlerMessage(Message msg){}};@overridepublic void onCreate(Bundle bundle){super.onCreate(bundle);setContextView(R.layout.activity_foo_layout);textView = (TextView)findViewById(R.id.textView);handler.postDelayed(new Runnable(){@overridepublic void run(){textView.setText(“ok”);};},1000 * 60 * 10);}}
錯誤原因:
當(dāng)我們執(zhí)行了FooActivity的finish方法,被延遲的消息會在被處理之前存在于主線程消息隊列中10分鐘,而這個消息中又包 含了Handler的引用,而Handler是一個匿名內(nèi)部類的實例,其持有外面的FooActivity的引用,所以這導(dǎo)致了FooActivity無 法回收,進(jìn)而導(dǎo)致FooActivity持有的很多資源都無法回收,所以產(chǎn)生了內(nèi)存泄露。
注意上面的new Runnable這里也是匿名內(nèi)部類實現(xiàn)的,同樣也會持有FooActivity的引用,也會阻止FooActivity被回收。
一個靜態(tài)的匿名內(nèi)部類實例不會持有外部類的引用。

正確方式:

public class FooActivity extends Activity{private TextView textView;private static class MyHandler extends Handler {private final WeakReference<FooActivity> mActivity;public MyHandler(FooActivity activity) {mActivity = new WeakReference<FooActivity>(activity);}@Overridepublic void handleMessage(Message msg) {FooActivity activity = mActivity.get();if (activity != null) {// ...}}}private final MyHandler handler = new MyHandler(this);@overridepublic void onCreate(Bundle bundle){super.onCreate(bundle);setContextView(R.layout.activity_foo_layout);textView = (TextView)findViewById(R.id.textView);handler.postDelayed(new MyRunnable(textView),1000 * 60 * 10);}private static class MyRunnable implements Runnable{private TextView textView; private WeakReference<TextView> textViewWeakReference;public MyRunnable(TextView textView){textViewWeakReference = new WeakReference<TextView>(textView);}@overridepublic void run(){final textView = textViewWeakReference.get();if(textView != null){textView.setText("OK");}};}}
3. 在使用handler后,記得在onDestroy里面handler.removeCallbacksAndMessages(object token);

// removeCallbacksAndMessages,當(dāng)參數(shù)為null的時候,可以清除掉所有跟次handler相關(guān)的Runnable和Message,我們在onDestroy中調(diào)用次方法也就不會發(fā)生內(nèi)存泄漏了 handler.removeCallbacksAndMessages(null);


開發(fā)中需要注意的點以免內(nèi)存泄漏:


? 1. 不要讓生命周期長于Activity的對象持有到Activity的引用


? 2. 盡量使用Application的Context而不是Activity的Context


? 3. 盡量不要在Activity中使用非靜態(tài)內(nèi)部類,因為非靜態(tài)內(nèi)部類會隱式持有外部類實例的引用(具體可以查看細(xì)話Java:”失效”的private修飾符了解)。如果使用靜態(tài)內(nèi)部類,將外部實例引用作為弱引用持有


? 4. 垃圾回收不能解決內(nèi)存泄露,了解Android中垃圾回收機制

獲取context的方法,以及使用上context和applicationContext的區(qū)別:

? 1. View.getContext,返回當(dāng)前View對象的Context對象,通常是當(dāng)前正在展示的Activity對象。

? 2. Activity.getApplicationContext,獲取當(dāng)前Activity所在的(應(yīng)用)進(jìn)程的Context對象,通常我們使用Context對象時,要優(yōu)先考慮這個全局的進(jìn)程Context。

? 3. ContextWrapper.getBaseContext():用來獲取一個ContextWrapper進(jìn)行裝飾之前的Context,可以使用這個方法,這個方法在實際開發(fā)中使用并不多,也不建議使用。

? 4. Activity.this 返回當(dāng)前的Activity實例,如果是UI控件需要使用Activity作為Context對象,但是默認(rèn)的Toast實際上使用ApplicationContext也可以。


數(shù)字1:啟動Activity在這些類中是可以的,但是需要創(chuàng)建一個新的task。一般情況不推薦。

數(shù)字2:在這些類中去layout inflate是合法的,但是會使用系統(tǒng)默認(rèn)的主題樣式,如果你自定義了某些樣式可能不會被使用。

數(shù)字3:在receiver為null時允許,在4.2或以上的版本中,用于獲取黏性廣播的當(dāng)前值。(可以無視)

注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因為在其內(nèi)部方法中都有一個context用于使用。

好了,這里我們看下表格,重點看Activity和Application,可以看到,和UI相關(guān)的方法基本都不建議或者不可使用 Application,并且,前三個操作基本不可能在Application中出現(xiàn)。實際上,只要把握住一點,凡是跟UI相關(guān)的,都應(yīng)該使用 Activity做為Context來處理;其他的一些操作,Service,Activity,Application等實例都可以,當(dāng)然了,注意 Context引用的持有,防止內(nèi)存泄漏。


本文參考:

? http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1123/2047.html

? http://droidyue.com/blog/2014/12/28/in-android-handler-classes-should-be-static-or-leaks-might-occur/

? http://droidyue.com/blog/2015/04/12/avoid-memory-leaks-on-context-in-android/

? http://blog.csdn.net/lmj623565791/article/details/40481055

總結(jié)

以上是生活随笔為你收集整理的android开发中,可能会导致内存泄露的问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。