在Android開發(fā)開發(fā)中,操作不當(dāng)很容易引起內(nèi)存泄漏,這里主要記錄下平時遇到問題,包括:靜態(tài)變量(也包含集合)、非靜態(tài)的內(nèi)部類、Handler、監(jiān)聽器,尤其是 Handler 在開發(fā)中要格外的注意。
1、靜態(tài)變量
public class LeakActivityDemo extends Activity{
? ? ? private static TextView mTextView;
? ? ? @Override
? ? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_main);
? ? ? ? mTextView = new TextView(this);
? ? ? ? mTextView.setText("demo");
? ? ? }
? ? }
我這里這是一個例子,一般開發(fā)不會這么寫,上面的代碼在 Activity 結(jié)束的時候,mTextView 一直持有 this 引用,
導(dǎo)致整個 Activity 無法回收
解決:方法在 Activity 生命周期 onDestroy 時將 mTextView 置空,或者盡量少使用到靜態(tài)變量。
注意:在寫代碼時,要考慮到當(dāng)前的變量是否持有當(dāng)前 Activity 的引用,避免出現(xiàn)內(nèi)存泄漏.
2、非靜態(tài)內(nèi)部類
關(guān)于 Handler
public class LeakActivity extends Activity{
? ? ? @Override
? ? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_main);
? ? ? ? mHandler.postDelayed(new Runnable() {
? ? ? ? ? @Override
? ? ? ? ? public void run() {
? ? ? ? ? }
? ? ? ? }, 1);
? ? ? }
? ? ? //提示:This Handler class should be static or leaks might occur (com.mvp.view.LeakActivity.1)
? ? ? private Handler mHandler = new Handler() {
? ? ? ? ? @Override public void handleMessage(Message msg) {
? ? ? ? ? ? ? super.handleMessage(msg);
? ? ? ? ? }
? ? ? };
? ? }
在 Android 開發(fā)中,我們一般使用 Handler 處理異步操作,通常我們的代碼會像上面一樣實現(xiàn),但是上面的代碼可能存在泄漏,其實編譯器已經(jīng)提示了警告,建議使用 static 靜態(tài)標(biāo)示。
原因:
1、首先在 java 中,非靜態(tài)內(nèi)部類會或者內(nèi)部類會持有外部對象的引用,而靜態(tài)內(nèi)部類不會持有外部類的引用;
2、和 Handler 機制有關(guān),我們知道 Handler 和 Looper 是一起工作的,在一個 Activity 起來的時候,會幫我們創(chuàng)建一個
在主線程中使用的 Looper,用來處理所有的消息,當(dāng) Hanlder 初始化好以后,就會有一個消息發(fā)送到了 Looper 的消息隊列中,
而這個消息則包含了當(dāng)前 Handler 的引用,這就是內(nèi)存泄露的原因;
解決:
1、使用靜態(tài)內(nèi)部類,如果在內(nèi)部類中使用了 Activiy 則要使用 WeakReference(弱引用),并且需要注意判空。
2、還有Hanlder要在生命周期 ondestroy 時,取消該 Handler 對象的 Messag 和 Runnable。
例如:
removeCallbacks(Runnable r)、removeMessages(int what)、mHandler.removeCallbacksAndMessages(null);
private final MyHandler mHandler = new MyHandler(this);
? public static class MyHandler extends Handler {
? ? ? private final WeakReference<LeakActivity> mWeakActivity;
? ? ? public MyHandler(LeakActivity context) {
? ? ? ? mWeakActivity = new WeakReference<LeakActivity>(context);
? ? ? }
? ? ? @Override public void handleMessage(Message msg) {
? ? ? ? ? super.handleMessage(msg);
? ? ? ? ? if (mWeakActivity.get() != null) {
? ? ? ? ? ? mWeakActivity.get().todo();
? ? ? }
? ? ? }
? }
? public void todo(){
? ? //todo
? }
關(guān)于 Runnable
常常會這么寫,會存在很大的內(nèi)存泄露問題,內(nèi)部類會持有外部對象的引用,如果我們 run 方法操作了 UI 等,或者 使用了 postDelayed 方法,很容易造成內(nèi)存泄露問題。
mHandler.post(new Runnable() {
? ? @Override
? ? public void run() {
? ? ? ..
? ? }
});
解決方法:使用靜態(tài)的Runnable 和 WeakReference 來解決引用問題,使用 WeakReference 要注意判斷,因為可能隨時會被回收。
private static final class ItemRunnble implements Runnable {
? private final WeakReference<Item> mWeakReference;
? public ProgressBarRunnble(Item f) {
? ? mWeakReference = new WeakReference<Item>(f);
? }
? @Override
? public void run() {
? ? Item item = mWeakReference.get();
? ? if (item != null) {
? ? ? ...
? ? }
? }
}
mHandler.post(new ItemRunnble(mItem))
3、非靜態(tài)內(nèi)部類生成的靜態(tài)變量
private static MyClass myClass;
? private class MyClass {
? }
..
myClass = new MyClass();?
這種是兩者的綜合體,只要是非靜態(tài)內(nèi)部類就會持有外部類的引用,如果外部類正好是 Activity ,那么會導(dǎo)致 Activity 無法回收;
處理方式和第一種很像,記得釋放
總結(jié)
靜態(tài)變量最容易出現(xiàn)內(nèi)存泄露,這些靜態(tài)變量的生命周期和應(yīng)用程序一致,所有的對象 Object 也不能被釋放,
而集合類如果不 remove 添加的 Object,則會永遠(yuǎn)持有這些 Ojbect,也會導(dǎo)致無法釋放。
監(jiān)聽器是一種使用方式,Android 中比較常見的是 Listener,Observer 等,
一般被監(jiān)聽者的生命周期要比監(jiān)聽者的生命周期長,當(dāng)監(jiān)聽者本身不被使用,但又沒有移除被監(jiān)聽者對其的引用時就會造成內(nèi)存無法釋放。
數(shù)據(jù)庫在不使用時也沒有關(guān)閉,那么這部分內(nèi)存也就無法回收。
以下列舉注意情況:
遵守生命周期,創(chuàng)建時創(chuàng)建,銷毀時記得回收
Bitmip 和 Drawable 記得手動回收
減少靜態(tài)變量的使用
自定義靜態(tài) Handler,和 Handler 回收
使用 Application Context,少使用 Activity Context
監(jiān)聽器不使用的時候記得釋放
如果循環(huán)中使用較多臨時變量,當(dāng)不使用時及時釋放
————————————————
版權(quán)聲明:本文為CSDN博主「無名無」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/cpfdpzc/article/details/53336146