LeakCanary2的免寫 初始化程式碼 原理
最近LeakCanary 做了升級,釋出了2.0版本,帶了了很多效能上的優化,不過一個很吸引我的點在於,他居然不像以前一樣,需要手動初始化了。
按照以前的使用流程,一般我們都是在dependencies 加入依賴
dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3' // Optional, if you use support library fragments: debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3' } 複製程式碼
接著在我們的application裡面加入初始化的邏輯。
public class ExampleApplication 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); // Normal app init code... } } 複製程式碼
但是,新版本的 LeakCanary 2.0居然可以不再需要寫這個操作,只需要在程式碼裡面加入這麼一句依賴就可以了
dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-1' } 複製程式碼
我有點懷疑自己的眼睛,重新看了下他們的Readme ,是不是真的
Getting started Add LeakCanary to yourbuild.gradle:
dependencies { debugImplementation com.squareup.leakcanary:leakcanary-android:2.0-alpha-1' }
You're good to go!LeakCanary will automatically show a notification when an activity or fragment memory leak is detected in your debug build.
好吧,確實是這樣,那麼到底怎麼做到的?很神奇啊,這怎麼也會有一個地方會需要初始化的,到底換到那裡去了?
在經過對原始碼的解讀後,發現了一個騷操作,感覺傳開後,以後的sdk庫都可能這麼做,教壞小朋友了。
ContentProvider
在經過對原始碼的閱讀後,發現其實人家是基於CP這個對於絕大數開發來說,基本沒用到的四大元件之一來做的,真的是服了哈哈。檢視他的leakcanary-leaksentry
模組的AndroidManifest.xml
檔案,可以看到下面的內容:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.squareup.leakcanary.leaksentry" > <application> <provider android:name="leakcanary.internal.LeakSentryInstaller" android:authorities="${applicationId}.leak-sentry-installer" android:exported="false"/> </application> </manifest> 複製程式碼
接著我們去看下那LeakSentryInstaller
這個類到底做了什麼。
internal class LeakSentryInstaller : ContentProvider() { override fun onCreate(): Boolean { CanaryLog.logger = DefaultCanaryLog() val application = context!!.applicationContext as Application InternalLeakSentry.install(application) //騷操作在這裡,利用系統自動呼叫CP的onCreate方法來做初始化 return true } override fun query( uri: Uri, strings: Array<String>?, s: String?, strings1: Array<String>?, s1: String? ): Cursor? { return null } override fun getType(uri: Uri): String? { return null } override fun insert( uri: Uri, contentValues: ContentValues? ): Uri? { return null } override fun delete( uri: Uri, s: String?, strings: Array<String>? ): Int { return 0 } override fun update( uri: Uri, contentValues: ContentValues?, s: String?, strings: Array<String>? ): Int { return 0 } } 複製程式碼
我們看到這個CP類,沒做任何的CURD操作,全是空的,就純粹利用系統會回撥這個介面來做初始化,幫助開發偷懶,省去呼叫寫初始化邏輯。
個人看待這個,覺得得分兩部門
好處:確實帶來了"免侵入"
,不需要業務人員寫任何程式碼。一般啟動的順序是Application->attachBaseContext =====>ContentProvider->onCreate =====>Application->onCreate =====>Activity->onCreate
所以對於大多數場景,寫在CP的初始化的實際是足夠優先了!!
壞處:這有點把CP給用歪了。以後所有人都這麼弄,接入的sdk都這麼寫的話,那就真的可愛了。