在项目开发过程中,性能检测分析是必不可少的一个环节,选择一款好的对口的工具能让我们事半功倍。LeakCanary是一款Square公司提供的检测内存泄漏的工具,LeakCanary使用起来非常方便,下面我们就来看下其基本用法,当然也可以直接查看官方文档:
我们首先在gradle中添加LeakCanary依赖,注意如果android studio3.0版本以后则需要使用debugImplementation这种依赖方式
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
随后在我们的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);
}
}
这就欧了,是不是非常方便,当LeakCanary在调试版本中检测到你的Activity发生内存泄漏时,你的通知栏就会收到其通知提醒。为了测试一下上面的几行代码是否就真的能实现我们的需求,我写了一段内存泄漏的代码,请叫我写bug小能手[笑哭]
public class CommentUtils {
public static CommentUtils utils;
private Context context;
public static CommentUtils getUtils(Context context) {
if(utils == null){
synchronized (CommentUtils.class) {
if(utils == null){
// 因为静态utils变量的生命周期等同程序生命周期
// 所以当utils持有activity的context时,会使activity始终存在着utils的强引用,导致该activity无法被销毁
// 解决办法1.使用context.getApplicationContext(),2.弱引用context
utils = new CommentUtils(context);
}
}
}
return utils;
}
private CommentUtils(Context context) {
this.context = context;
}
}
随后在我们的类中,使用该内存泄漏的代码,非常简单的代码
public class MonitoringActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_monitoring);
CommentUtils utils = CommentUtils.getUtils(this);
}
}
好了,接下来我们横竖屏切换,让我们的MonitoringActivity类执行onDestroy销毁掉,等待几秒钟(我测试了HUAWEI和OPPO,两个手机的等待时间不同),随后我们的通知栏就会出现通知:
当你的系统在6.0以上,LeakCanary首先会发送一条通知告知你没有权限,点击该通知条允许app获得权限,随后就能够正常接收内存泄漏的通知,点击并可以查看当前泄漏详情:
好了,Activity的内存泄漏检测到这里就介绍完了,但是如果你需要检测Fragment,这样做其实还是不够的,不过也很简单,我们来简单看一下,这是我们的Application类,我们需要一个RefWatcher类来监听我们的Fragment
public class MyApplication extends Application {
public static RefWatcher getRefWatcher(Context context) {
MyApplication application = (MyApplication) context.getApplicationContext();
return application.refWatcher;
}
//程序运行的时候会创建一个Application 对象,且仅创建一个,而且Application 的生命周期等于程序的生命周期,所以我们所使用的refWatcher都是同一个
private RefWatcher 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;
}
refWatcher = LeakCanary.install(this);
}
}
随后在我们的Fragment中,当Fragment销毁的时候,refWatcher.watch(fragment)
public class MonitoringFragment extends Fragment {
RefWatcher refWatcher;
@Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_monitoring, container, false);
//这里在CommentUtils里重载了一个getUtils方法,目的是让utils 持有fragment,造成内存泄漏
CommentUtils utils = CommentUtils.getUtils(this);
return view;
}
@Override public void onDestroy() {
super.onDestroy();
refWatcher = MyApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}