leakcanary的使用以及常见的泄露

1.gradle 引用

debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
//testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'

2.使用

在自己的Application的onCreate()中调用

if (AppConfig.IS_DEBUG) {
    refWatcher = LeakCanary.install(this);
}

AppConfig.IS_DEBUG是我定义的一个常量,在buildTypes进行赋值,进行自己来管理DEBUG状态

buildTypes {
    release {
        minifyEnabled false
        signingConfig signingConfigs.debug
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        buildConfigField "boolean", "IS_DEBUG", "false"
        buildConfigField "boolean", "IS_LOG", "false"

    }
    debug {
        signingConfig signingConfigs.debug

        buildConfigField "boolean", "IS_DEBUG", "true"
        buildConfigField "boolean", "IS_LOG", "true"
    }
}

3.典型泄露

3.1查看泄露情况

简单情况下,是用了leakcanary,运行程序时会在测试机上安装一个APP,可以在这里查看。

leakcanary的使用以及常见的泄露_第1张图片

也可以通过,Android studio来查看详情,打开这个路径

leakcanary的使用以及常见的泄露_第2张图片

打开后,找到设备中,对应APP的hprof文件

leakcanary的使用以及常见的泄露_第3张图片

双击hprof文件,打开

leakcanary的使用以及常见的泄露_第4张图片

 

leakcanary的使用以及常见的泄露_第5张图片

打开分析,然后运行

leakcanary的使用以及常见的泄露_第6张图片

就可以看到具体的泄漏情况了

leakcanary的使用以及常见的泄露_第7张图片

 

3.2工具类静态变量,使用非Application上下文创建泄露

这是我定义的一个toast工具类,static Toaster mToaster;mToaster是static的,因为它的生命周期是跟随Application 的,如果使用activity之类来创建,就会在activity销毁后还保留该activity的引用,就导致了泄露。

public class Toaster {
    private Toast mToast;
    private Handler mHandler;

    private TextView mText;
    private Runnable lastRun;


    private Toaster(){
        Looper mainLooper = Looper.getMainLooper();
        mHandler=new Handler(mainLooper);
    }

    private static Toaster mToaster;


    public static Toaster getToaster(){

        if (mToaster == null) {
            mToaster=new Toaster();
        }
        return mToaster;
    }


    public void show(final String text){

        if (!TextUtils.isEmpty(text)){

            if (mToast == null) {
                mToast=new Toast(App.instance);

                LayoutInflater mInflate= (LayoutInflater) App.instance.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                View inflate = mInflate.inflate(R.layout.toast_layout, null);
                mText = ((TextView) inflate.findViewById(R.id.message));
                mToast.setView(inflate);
                mToast.setDuration(Toast.LENGTH_SHORT);
                //mToast.setGravity(Gravity.CENTER_HORIZONTAL,0,0);
            }
            if (lastRun != null) {
                mHandler.removeCallbacks(lastRun);
            }
            mHandler.post(lastRun= new Runnable() {
                @Override
                public void run() {
                    mText.setText(text);
                    mToast.show();
                }
            });

        }

    }
}

3.3 MediaPlayer的内存泄漏

mediaPlayer使用,释放不正确导致泄露,正确的写法应该这样

if (mediaPlayer != null) {
    mediaPlayer.stop();

    /*查看了Mediaplayer的源码,发现存在一个引用,应该回收,但是在release方法中,并没有没处理,只有在reset方法中,这个引用才被消除。 */
    mediaPlayer.reset();

    mediaPlayer.release();
    mediaPlayer = null;
}

leakcanary的使用以及常见的泄露_第8张图片

leakcanary的使用以及常见的泄露_第9张图片

 

 

你可能感兴趣的:(android技巧)