LeakCanary 2 is a major rewrite. High level changes:
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' }
dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:{{ leak_canary.release }}' }
leakcanary-android-no-op artifact is gone. If you have compile errors, see below.leakcanary-android as debugImplementation, there won't be any code referencing LeakCanary in your release builds.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... } }
There is no more code for default setup.
LeakCanary.isInAnalyzerProcess().val refWatcher: RefWatcher = LeakCanary.installedRefWatcher()
val objectWatcher: ObjectWatcher = AppWatcher.objectWatcher
If you were using RefWatcher in non debug code, you now get a compile error because the no-op artifact is gone. ObjectWatcher now lives in the object-watcher artifact, which is suitable for release builds. You have two options:
object-watcher-android to release builds.dependencies { implementation 'com.squareup.leakcanary:leakcanary-object-watcher-android:{{ leak_canary.release }}' }
val retainedObjectCount = AppWatcher.objectWatcher.retainedObjectCount
ObjectWatcher interface// In shared code interface MaybeObjectWatcher { fun watch(watchedObject: Any, description: String) object None : MaybeObjectWatcher { override fun watch(watchedObject: Any, description: String) { } } } // In debug code class RealObjectWatcher : MaybeObjectWatcher { override fun watch(watchedObject: Any, description: String) { AppWatcher.objectWatcher.watch(watchedObject, description) } }
Use MaybeObjectWatcher.None in release code and RealObjectWatcher in debug code.
public class DebugExampleApplication extends ExampleApplication { @Override protected void installLeakCanary() { RefWatcher refWatcher = LeakCanary.refWatcher(this) .watchActivities(false) .buildAndInstall(); } }
AppWatcher is in charge of detecting retained objects. Its configuration can be updated at any time by replacing AppWatcher.config:
class DebugExampleApplication : ExampleApplication() { override fun onCreate() { super.onCreate() AppWatcher.config = AppWatcher.config.copy(watchFragmentViews = false) } }
LeakCanary is in charge of taking heap dumps and analyzing them. Its configuration can be updated at any time by replacing LeakCanary.config:
disableLeakCanaryButton.setOnClickListener { LeakCanary.config = LeakCanary.config.copy(dumpHeap = false) }
In your build.gradle file:
dependencies { androidTestImplementation "com.squareup.leakcanary:leakcanary-android-instrumentation:${leakCanaryVersion}" } android { defaultConfig { // ... testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArgument "listener", "com.squareup.leakcanary.FailTestOnLeakRunListener" } }
In your test Application class:
public class InstrumentationTestExampleApplication extends DebugExampleApplication { @Override protected void installLeakCanary() { InstrumentationLeakDetector.instrumentationRefWatcher(this) .buildAndInstall(); } }
Remove all the previous test related leak detection code then follow Leak detection in UI tests.
public class LeakUploadService extends DisplayLeakService { @Override protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) { // TODO Upload result to server } }
RefWatcher refWatcher = LeakCanary.refWatcher(this) .listenerServiceClass(LeakUploadService.class) .buildAndInstall();
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:name="com.example.DebugExampleApplication"> <service android:name="com.example.LeakUploadService" /> </application> </manifest>
class LeakUploader : OnHeapAnalyzedListener { val defaultListener = DefaultOnHeapAnalyzedListener.create() override fun onHeapAnalyzed(heapAnalysis: HeapAnalysis) { TODO("Upload heap analysis to server") // Delegate to default behavior (notification and saving result) defaultListener.onHeapAnalyzed(heapAnalysis) } } class DebugExampleApplication : ExampleApplication() { override fun onCreate() { super.onCreate() LeakCanary.config = LeakCanary.config.copy( onHeapAnalyzedListener = LeakUploader() ) } }
ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults() .staticField("com.samsing.SomeSingleton", "sContext") .build(); RefWatcher refWatcher = LeakCanary.refWatcher(this) .excludedRefs(excludedRefs) .buildAndInstall(); }
LeakCanary.config = LeakCanary.config.copy( referenceMatchers = AndroidReferenceMatchers.appDefaults + AndroidReferenceMatchers.staticFieldLeak( "com.samsing.SomeSingleton", "sContext" ) )
!!! info There is no equivalent API to ExcludedRefs.Builder.clazz() because it led to abuses. Instead see Ignoring specific activities or fragment classes.
All public APIs were in com.squareup.leakcanary.*
All public APIs are in leakcanary.*