LeakCanary有回调吗?

Does LeakCanary has callback?

如何获取 LeakCanary 日志或有关泄漏的任何类型的数据? LeakCanary 是否有任何类型的回调,我们可以使用它来让 "leak data" 在它发生时对其进行处理? 我想将数据发送到我的 FireBase 或其他数据库。

我在文档中进行了搜索,但没有找到相关信息。

感谢大家

TLDR;你需要扩展 DisplayLeakService

https://github.com/square/leakcanary/wiki/Customizing-LeakCanary#uploading-to-a-server

您可以更改默认行为以将泄漏跟踪和堆转储上传到您选择的服务器。

创建您自己的 AbstractAnalysisResultService。最简单的方法是在调试源中扩展 DisplayLeakService:

public class LeakUploadService extends DisplayLeakService {
  @Override protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
    if (!result.leakFound || result.excludedLeak) {
      return;
    }
    if (result.leakFound) {
      uploadLeakToServer(result, leakInfo);
    }
  }

  private void uploadLeakToServer(AnalysisResult result, String leakInfo) {
    // TODO Upload result to server
  }
}

您可以使用 AnalysisResult.leakTraceAsFakeException() 将泄漏跟踪转换为虚假异常,并将它们上传到崩溃报告后端。以下是使用 Bugsnag 的方法:

public class LeakUploadService extends DisplayLeakService {

  @Override protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) {
    if (!result.leakFound || result.excludedLeak) {
      return;
    }
    if (result.leakFound) {
      uploadLeakToServer(result, leakInfo);
    }
  }

  private void uploadLeakToServer(AnalysisResult result, String leakInfo) {
    Client bugsnagClient = new Client(getApplication(), "YOUR_BUGSNAG_API_KEY", false);
    bugsnagClient.setSendThreads(false);
    bugsnagClient.beforeNotify(error -> {
      // Bugsnag does smart grouping of exceptions, which we don't want for leak traces.
      // So instead we rely on the SHA-1 of the stacktrace, which has a low risk of collision.
      String stackTraceString = Logs.getStackTraceString(error.getException());
      String uniqueHash = Strings.createSHA1Hash(stackTraceString);
      error.setGroupingHash(uniqueHash);
      return true;
    });

    MetaData metadata = new MetaData();
    metadata.addToTab("LeakInfo", "LeakInfo", leakInfo);
    bugsnagClient.notifyBlocking(result.leakTraceAsFakeException(), Severity.ERROR, metadata);
  }
}

接下来需要在LeakCanary中指定监听服务class:

public class DebugExampleApplication extends ExampleApplication {
  @Override protected void installLeakCanary() {
    RefWatcher refWatcher = LeakCanary.refWatcher(this)
      .listenerServiceClass(LeakUploadService.class);
      .buildAndInstall();
  }
}

不要忘记在调试中注册服务 AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    >
  <application android:name="com.example.DebugExampleApplication">
    <service android:name="com.example.LeakUploadService" />
  </application>
</manifest>

我的解决方案有点不同(基于 square 中的样本:https://square.github.io/leakcanary/recipes/#uploading-to-bugsnag),但思路是一样的。我们通过 Timber 使用 Sentry 和 Firebase 来记录内存泄漏。我发现哨兵日志记录更方便一些,因为它显示了我在发生内存泄漏之前采取的确切步骤(屏幕打开,background/foreground)。

/**
 * Helper class to record leak canary memory leak traces on Timber.
 */
class LeakCanaryService : OnHeapAnalyzedListener {

    private val defaultLeakListener = DefaultOnHeapAnalyzedListener.create()

    override fun onHeapAnalyzed(heapAnalysis: HeapAnalysis) {
        // Delegate to default behavior (notification and saving result)
        defaultLeakListener.onHeapAnalyzed(heapAnalysis)

        when (heapAnalysis) {
            is HeapAnalysisSuccess -> {
                val allLeakTraces = heapAnalysis
                    .allLeaks
                    .toList()
                    .flatMap { leak ->
                        leak.leakTraces.map { leakTrace -> leak to leakTrace }
                    }

                allLeakTraces.forEach { (leak, leakTrace: LeakTrace) ->
                    val exception = MemoryLeakReportingException(leak.shortDescription)
                    Timber.e(exception, "Memory leak recorded: ${exception.message}\n$leakTrace")
                }

            }
            is HeapAnalysisFailure -> {
                // Please file any reported failure to
                // https://github.com/square/leakcanary/issues
                Timber.e(
                    heapAnalysis.exception,
                    "Memory leak analysis failed: ${heapAnalysis.exception.message}"
                )

            }
        }
    }

    class MemoryLeakReportingException(message: String) : RuntimeException(message)

}

您在应用中初始化此 class class:

LeakCanary.config = LeakCanary.config.copy(
    onHeapAnalyzedListener = LeakCanaryService()
)