LeakCanary初见

一、前言

在项目开发过程中,性能检测分析是必不可少的一个环节,如果自己用MAT工具分析,或者用UIAnmatior等工具分析 也是可以做到,但工欲善其事必先利其器,有一个好的工具对我们开发还是很想帮助的,能让我们把精力更多的放在代码的优化和设计上。这也正是Google一直想让我们开发者做的事情。在开源的大环境下有很多可以检测内存泄漏的手段和第三方库,今天我们就来介绍一款堪称神器的内存泄露检查工具,LeakCanary。它是一款由Square公司提供的检测内存泄漏的工具,LeakCanary使用起来非常简单,不信跟我来。

二、基本使用

我们首先在gradle中添加LeakCanary依赖,注意如果android studio3.0版本以后则需要使用debugImplementation这种依赖方式

debugImplementation'com.squareup.leakcanary:leakcanary-android:1.6.3'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'

随后在我们的Application类中,开始启动LeakCanary

public class MyApplication extends Application {
@Override public void onCreate() {
     super.onCreate();
  if (LeakCanary.isInAnalyzerProcess(this)) {
    // This process is dedicated to LeakCanary for heap analysis.
    // You should not init your app in this process.
    return;
  }
  LeakCanary.install(this);
  }
}

并且在 Manifest中 在application节点中添加name属性,写入你自定义的Application类

    <application
        android:name="MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"

当LeakCanary在调试版本中检测到你的Activity发生内存泄漏时,你的通知栏就会收到其通知提醒。为了测试一下上面的几行代码是否就真的能实现我们的需求,我们人为的写入一个一定会发生内存泄漏的代码:

public class LeakUtils {
    public static LeakUtils utils;
    private Context context;

    public LeakUtils(Context context) {
        this.context = context;
    }

    public static LeakUtils getUtils(Context context) {
        if (utils == null) {
            synchronized (LeakUtils.class) {
                if (utils == null) {
                    // 因为静态utils变量的生命周期等同程序生命周期
                    // 所以当utils持有activity的context时,会使activity始终存在着utils的强引用,导致该activity无法被销毁
                    // 解决办法1.使用context.getApplicationContext(),
                    // 2.弱引用context
                    utils = new LeakUtils(context);
                }
            }
        }
        return utils;
    }
}
private CommentUtils(Context context) {

  this.context = context;

}

}

随后在我们的类中,使用该内存泄漏的代码

public class MainActivity extends AppCompatActivity {

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

        LeakUtils utils = LeakUtils.getUtils(this);
    }
}

由于LeakCanary是在onDestroy之后才去分析GC后,是否有引用的。我们需要手动让我们的程序执行到onDestroy回调方法上,最简单的办法就是横竖屏切换,等待几秒钟(不同手机执行需要的时间不太一样),随后我们的通知栏就会出现通知:这里需要提醒下,在6.0系统以上,LeakCanary首先会发送一条通知请求权限

点击该通知条允许app获得权限,

随后就能够正常接收内存泄漏的通知,点击并可以查看当前泄漏详情

Activity的内存检测就这么简单。但是如果你需要检测Fragment就需要一个 RefWatcher来监听我们的Fragment

public class MyFragmentApplication extends Application {
    //程序运行的时候会创建一个Application 对象,且仅创建一个,
    // 而且Application 的生命周期等于程序的生命周期,所以我们所使用的refWatcher都是同一个
    private RefWatcher refWatcher;
    public static RefWatcher getRefWatcher(Context context) {
        MyFragmentApplication application = (MyFragmentApplication) context.getApplicationContext();
        return application.refWatcher;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        if (LeakCanary.isInAnalyzerProcess(this)) {
            // This process is dedicated to LeakCanary for heap analysis.
            // You should not init your app in this process.
            return;
        }
        //这里比Activity多的就是获得了LeakCanary.install的值
        refWatcher = LeakCanary.install(this);
    }
}

随后在我们的Fragment中,当Fragment销毁的时候,refWatcher.watch(fragment)
 

public class MyFragment extends Fragment {
    RefWatcher mRefWatcher;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = LayoutInflater.from(getActivity()).
                inflate(R.layout.fragment_main, container, false);
        //为了简单起见,这里我们偷懒让LeakUtils重载getUtils
        LeakUtils utils = LeakUtils.getUtils(this);
        return view;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mRefWatcher = MyFragmentApplication.getRefWatcher(getActivity());
        mRefWatcher.watch(this);
    }
}

然后在Activity中添加Fragment

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/show_leak_fragment"
        android:name="com.josfloy.xingnengdemo.MyFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

随后信息就以通知的形式反馈给我们

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值