1. 程式人生 > >android.view.WindowLeaked: Activity

android.view.WindowLeaked: Activity

轉載請註明出處:https://blog.csdn.net/u011038298/article/details/84138185

 

記憶體洩露的原因:

當一個物件無需被使用時,應該被回收,但是當另外一個物件還持有對該物件的引用時,這樣就會導致該物件無法被GC回收,所以就會出現記憶體洩露的情況。

 

記憶體洩露場景一: 

import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private Dialog mDialog;

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

        // 初始化對話方塊
        mDialog = new Dialog(this);
        View contentView = LayoutInflater.from(MainActivity.this).inflate(R.layout.dialog_test, null);
        mDialog.setContentView(contentView);
        mDialog.setTitle("演示");
        mDialog.show();

        // 結束當前介面
        finish();
    }

}

問題原因:當前activity被finish掉了,但是依附在當前activity的dialog卻沒有被關閉掉,造成記憶體洩露

解決方案:在activity的onDestory函式中加入判斷: if (mDialog!=null && mDialog.isShowing()) { mDialog.dismiss(); }

 

記憶體洩露場景二: 

import android.content.Context;

public class Test {

    private Context mContext;
    private static Test instance;

    private Test(Context context) {
        this.mContext = context;
        // 應該改為context.getApplicationContext()
        // this.mContext = context.getApplicationContext();
    }

    public static Test getInstance(Context context) {
        if (instance != null) {
            instance = new Test(context);
        }
        return instance;
    }

}

問題原因:當前activity被finish掉了,Context也會隨著Activity被銷燬,但是單例還持有該物件的引用,這時就會造成記憶體洩露。

解決方案:把context改為Application的Context,因為Application的Context生命週期跟隨著整個應用程式的生命週期。

 

記憶體洩露場景三: 

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler.sendEmptyMessage(0);
    }

}

 問題原因:當使用內部類(包括匿名類)來建立Handler的時候,Handler物件會隱式地持有一個外部類物件(通常是一個Activity)的引用。如果activity被finish掉了,而handler還在工作的話,這時handler又持有Activity的引用,就導致該Activity無法被回收,造成記憶體洩露。

解決方案:可以在Activity的onDestroy()函式中呼叫Handler.removeCallbacksAndMessages(null); 也可以將Handler宣告為靜態類。在Java 中,非靜態的內部類和匿名內部類都會隱式地持有其外部類的引用,靜態的內部類不會持有外部類的引用。靜態類不持有外部類的物件,所以你的Activity可以隨意被回收。如果將Handler宣告為靜態類,請注意由於Handler不再持有外部類物件的引用,導致程式不允許你在Handler中操作Activity中的物件了,所以你需要在Handler中增加一個對Activity的弱引用。

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity {

    private static class MyHandler extends Handler {

        private WeakReference<MainActivity> mWeakReference;

        public MyHandler(MainActivity activity) {
            mWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            final MainActivity activity = mWeakReference.get();
            if (activity != null) {
                switch (msg.what) {
                    case 0:
                        break;
                }
            }
        }
    }

    private MyHandler mHandler;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler = new MyHandler(this);
        mHandler.sendEmptyMessage(0);
    }

}