转载请注明出处:http://blog.csdn.net/llew2011/article/details/52958567
在上边文章Android 源码系列之<十三>从源码的角度深入理解LeakCanary的内存泄露检测机制(中)由于篇幅原因仅仅向小伙伴们讲述了在Android开发中如何使用LeakCanary来检测应用中出现的内存泄露,并简单的介绍了LeakCanary的相关配置信息。根据上篇文章的介绍我们知道LeakCanary为了不给APP进程造成影响所以新开启了一个进程,在新开启的进程中做内存泄露检测,这篇文章将要带领小伙伴们从源码的角度出发深入了解一下LeakCanary的内存泄露检测机制,希望能给小伙伴们一点帮助,如果你对LeakCanary的原理非常熟悉了,请跳过本文(*^__^*) ……
当在项目中引入了LeakCanary后,就是进行LeakCanary的安装操作,初始化操作流程如下所示:
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 判断是否是LeakCanary的分析进程
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
// 初始化LeakCanary
LeakCanary.install(this);
}
}
安装LeakCanary前先判断当前进程是否是HeapAnalyzerService所在的远程分析进程,如果是分析进程就直接返回因为分析进程只是来分析堆信息是否存在内存泄露,否则调用LeakCanary的install()方法,该方法就是入口,我们跟进去,源码如下:
/**
* Creates a {@link RefWatcher} that works out of the box, and starts watching activity
* references (on ICS+).
*/
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
install()方法内部通过链式调用最终返回了一个RefWatcher对象,该对象就是来监听哪些对象是否发生内存泄露的,refWatcher()方法返回AndroidRefWatcherBuilder对象以后都是调用该对象的链式方法,其中excludeRefs()方法表示排除掉由Android SDK引发的内存泄露,因为Android SDK引发的内存泄露并非我们程序造成如果检测到是Android SDK引发的就不会报告给用户(如果想详细了解SDK引发的内存泄露信息可自行查看AndroidExcludedRefs类,该类有详细说明)。最后调用的是buildAndInstall()方法,该方法源码如下:
/**
* Creates a {@link RefWatcher} instance and starts watching activity references (on ICS+).
*/
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
LeakCanary.enableDisplayLeakActivity(context);
ActivityRefWatcher.installOnIcsPlus((Application) context, refWatcher);
}
return refWatcher;
}
buildAndInstall()方法中调用build()方法获取一个RefWatcher对象refWatcher并最终把refWatcher返回,当时在返回之前做了一个判断,若refWatcher不是DISABLED对象时就先后调用了LeakCanary的静态enableDisplayLeakActivity()方法和ActivityRefWatcher的静态installOnIcsPlus()方法。为什么要判断refWatcher对象是不是DISABLED呢?是因为在打包的时候如果当前模式是DEBUG模式那么refWatcher就不是DISABLED,否则就是DISABLED。这是间接的判断打包模式来决定时候安装LeakCanary库。
LeakCanary的静态方法enableDisplayLeakActivity()是动态的设定DisplayLeakActivity为可用状态,因为在上篇文章中介绍过DisplayLeakActivity默认是不可用的。ActivityRefWatcher的installOnIcsPlus()方法是真正的安装LeakCanary库的,该方法源码如下:
public static void installOnIcsPlus(Application application, RefWatcher refWatcher) {
if (SDK_INT < ICE_CREAM_SANDWICH) {
// 如果当前SDK版本号小于4.0则直接返回
// If you need to support Android < ICS, override onDestroy() in your base activity.
return;
}
ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher);
activityRefWatcher.watchActivities();
}
installOnIcsPlus()方法先判断当前SDK版本号,如果SDK版本号低于4.0则什么都不做就直接返回了,那也就是说LeakCanary库在Android4.0之前是没法直接使用的,若要在4.0之前使用就需要在基类BaseActivity的onDestroy()方法中调用RefWatcher的watch()方法来监控。接着是创建了一个ActivityRefWatcher实例对象并调用该对象的watchActivities()方法,根据方法名字就知道是监控Activity的,跟进源码看一下该方法,源码如下:
public void watchActivities() {
// Make sure you don't get installed twice.
// 开始监控Activity之前先尝试移除已经添加过的回调,确保只添加一次
stopWatchingActivities();
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
}
public void stopWatchingActivities() {
// 移除Application中已经添加的回调接口
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks);
}
通过阅读watchActivities()方法发现原来LeakCanary是巧妙的利用了Android 4.0之后的API,因为在4.0之后Google给Application添加了Activity的生命周期回调接口,如果我们注入了该回调接口,那么当Activity的声明周期发生变化的时候就会回调相关方法。我们看一下注入的回调接口lifecycleCallbacks,源码如下:
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@