{"record":{"id":"471c0bd09a818d70","repo":"didi/DoKit","slug":"buildandinstall-should-only-be-called-once","errorCode":null,"errorMessage":"buildAndInstall() should only be called once.","messagePattern":"buildAndInstall\\(\\) should only be called once\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/AndroidRefWatcherBuilder.java","lineNumber":96,"sourceCode":"  AndroidRefWatcherBuilder maxStoredHeapDumps(int maxStoredHeapDumps) {\n    LeakDirectoryProvider leakDirectoryProvider =\n        new DefaultLeakDirectoryProvider(context, maxStoredHeapDumps);\n    LeakCanary.setLeakDirectoryProvider(leakDirectoryProvider);\n    return self();\n  }\n\n  /**\n   * Creates a {@link RefWatcher} instance and makes it available through {@link\n   * LeakCanary#installedRefWatcher()}.\n   *\n   * Also starts watching activity references if {@link #watchActivities(boolean)} was set to true.\n   *\n   * @throws UnsupportedOperationException if called more than once per Android process.\n   */\n  public @NonNull\n  RefWatcher buildAndInstall() {\n    if (LeakCanaryInternals.installedRefWatcher != null) {\n      throw new UnsupportedOperationException(\"buildAndInstall() should only be called once.\");\n    }\n    RefWatcher refWatcher = build();\n    if (refWatcher != RefWatcher.DISABLED) {\n      if (enableDisplayLeakActivity) {\n        LeakCanaryInternals.setEnabledAsync(context, DisplayLeakActivity.class, true);\n      }\n      if (watchActivities) {\n        ActivityRefWatcher.install(context, refWatcher);\n      }\n      if (watchFragments) {\n        FragmentRefWatcher.Helper.install(context, refWatcher);\n      }\n    }\n    LeakCanaryInternals.installedRefWatcher = refWatcher;\n    return refWatcher;\n  }\n\n  @Override","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit-leakcanary/src/main/java/com/squareup/leakcanary/AndroidRefWatcherBuilder.java#L78-L114","documentation":"LeakCanary's AndroidRefWatcherBuilder.buildAndInstall() registers a process-wide singleton RefWatcher in LeakCanaryInternals.installedRefWatcher and starts activity/fragment watchers. It deliberately throws UnsupportedOperationException on a second call to prevent duplicated watchers, duplicate heap analysis, and duplicated notifications.","triggerScenarios":"Calling LeakCanary.refWatcher(context).buildAndInstall() (or a custom builder chain) more than once in the same process: once in Application.onCreate and again in a debug initializer, a test setup, a library module, or after a manual install in a multi-dex/provider startup path.","commonSituations":"App + SDK both initializing LeakCanary (DoraemonKit's dokit-leakcanary module plus app-level init). Adding LeakCanary setup to a ContentProvider that runs before Application.onCreate where it is also installed. Tests that call buildAndInstall in setUp without resetting LeakCanaryInternals.installedRefWatcher.","solutions":["Initialize LeakCanary in exactly one place, typically Application.onCreate()","Guard the install: if (LeakCanary.isInAnalyzerProcess(this)) return; before calling buildAndInstall in multi-process apps","Before a second install attempt (tests, plugins), check LeakCanary.installedRefWatcher != null or refactor to a single owner of initialization"],"exampleFix":"// before\nLeakCanary.refWatcher(this).buildAndInstall(); // called in Application AND in a provider\n\n// after\n// single init point in Application.onCreate()\nif (LeakCanary.isInAnalyzerProcess(this)) {\n  return;\n}\nif (LeakCanary.installedRefWatcher() == null) {\n  LeakCanary.refWatcher(this).buildAndInstall();\n}","handlingStrategy":"validation","validationCode":"if (LeakCanary.isInAnalyzerProcess(context)) return;\nif (LeakCanary.installedRefWatcher() == null) { LeakCanary.refWatcher(context).buildAndInstall(); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Initialize LeakCanary in exactly one place (Application.onCreate)","Audit SDKs (e.g. DoraemonKit modules) that may also call buildAndInstall"],"tags":["leakcanary","android","initialization","singleton","java"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}