【问题标题】:Does LeakCanary has callback?LeakCanary 有回调吗?
【发布时间】:2018-12-13 15:11:02
【问题描述】:

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

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

谢谢大家

【问题讨论】:

    标签: android leakcanary


    【解决方案1】:

    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 中指定监听服务类:

    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>
    

    【讨论】:

    • 非常感谢,我稍后再查
    【解决方案2】:

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

    /**
     * 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)
    
    }
    

    你在 App 类中初始化这个类:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-12
      • 2019-02-16
      • 2017-01-31
      • 1970-01-01
      • 1970-01-01
      • 2012-03-26
      相关资源
      最近更新 更多