问题1. LeakCanary 用了contentprovider来初始化,为什么用ContentProvider呢?
问题2. 多了一个图标怎么出现的?
问题3. 内存泄漏检测原理是什么?
回答问题1
- 是为了初始化方便,无侵入感
- 如果一个第三方库仅需要在 Application 中初始化,又并不需要调用任何 API 的库将会带给开发者一种无任何侵入式的感受,那么在ContentProvider中初始化是一个很好的选择。
- 那么 ContentProvider 的 onCreate() 方法是什么时候被调用的呢?它是介于 Application 的 attachBaseContext(Context) 和 onCreate() 之间所调用的,Application 的 attachBaseContext(Context) 方法被调用这就意味着 Application 的 Context 被初始化了。
然后在 ContentProvider 的 onCreate() 方法中借助 getContext() 返回的 Context 来完成你的库初始化,当然,这个 Context 的实际类型就是应用的 Application。
回答问题2
在调用 LeakCanary.install(this) 时,点进源码,会看到这样一行代码
enableDisplayLeakActivity(application);
这行代码最终执行的是
public static void setEnabledBlocking(Context appContext, Class<?> componentClass, boolean enabled) {
ComponentName component = new ComponentName(appContext, componentClass);
PackageManager packageManager = appContext.getPackageManager();
int newState = enabled?1:2;
packageManager.setComponentEnabledSetting(component, newState, 1);
}
这里的 componentClass 是 DisplayLeakActivity.class, 在 AndroidManifest.xml 文件中声明这个 Activity 时,设置 android:enabled="false", 然后再在代码中动态这样设置,就会在桌面上生成新的图标,作为 Activity 的入口。
回答问题3
LeakCanary 内存泄露检测步骤
1.利用 application.registerActivityLifecycleCallbacks(lifecycleCallbacks) 来监听整个生命周期内的 Activity onDestroyed 事件;
2.当某个 Activity 被 destroy 后,将它传给 RefWatcher 去做观测,确保其后续会被正常回收;
3.RefWatcher 首先把 Activity 使用 KeyedWeakReference 引用起来,并使用一个 ReferenceQueue 来记录该 KeyedWeakReference 指向的对象是否已被回收;
4.AndroidWatchExecutor 会在 5s 后,开始检查这个弱引用内的 Activity 是否被正常回收。判断条件是:若 Activity 被正常回收,那么引用它的 KeyedWeakReference 会被自动放入 ReferenceQueue 中。
5.判断方式是:先看 Activity 对应的 KeyedWeakReference 是否已经放入 ReferenceQueue 中;如果没有,则手动 GC:gcTrigger.runGc();然后再一次判断 ReferenceQueue 是否已经含有对应的 KeyedWeakReference。若还未被回收,则认为可能发生内存泄漏。(System.gc() 只是建议垃圾回收器来执行回收,不能保证触发即时回收。LeakCanary直接使用了Runtime.getRuntime().gc();)
6.利用 HeapAnalyzer 对 dump 的内存情况进行分析并进一步确认,若确定发生泄漏,则利用 DisplayLeakService 发送通知。
网友评论