{"record":{"id":"5acf6c0a4c49896d","repo":"didi/DoKit","slug":"singleton-instance-already-exists","errorCode":null,"errorMessage":"Singleton instance already exists.","messagePattern":"Singleton instance already exists\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/DokitPicasso.java","lineNumber":678,"sourceCode":"    if (singleton == null) {\n      synchronized (DokitPicasso.class) {\n        if (singleton == null) {\n          singleton = new Builder(context).build();\n        }\n      }\n    }\n    return singleton;\n  }\n\n  /**\n   * Set the global instance returned from {@link #with}.\n   * <p>\n   * This method must be called before any calls to {@link #with} and may only be called once.\n   */\n  public static void setSingletonInstance(DokitPicasso picasso) {\n    synchronized (DokitPicasso.class) {\n      if (singleton != null) {\n        throw new IllegalStateException(\"Singleton instance already exists.\");\n      }\n      singleton = picasso;\n    }\n  }\n\n  /** Fluent API for creating {@link DokitPicasso} instances. */\n  @SuppressWarnings(\"UnusedDeclaration\") // Public API.\n  public static class Builder {\n    private final Context context;\n    private Downloader downloader;\n    private ExecutorService service;\n    private Cache cache;\n    private Listener listener;\n    private RequestTransformer transformer;\n    private List<RequestHandler> requestHandlers;\n    private Bitmap.Config defaultBitmapConfig;\n\n    private boolean indicatorsEnabled;","sourceCodeStart":660,"sourceCodeEnd":696,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/DokitPicasso.java#L660-L696","documentation":"setSingletonInstance(DokitPicasso) installs the object returned by with(); it may be called at most once and only before the first with() call. A second call — or any call after with() already lazily created the default — throws IllegalStateException('Singleton instance already exists.'). This protects callers that captured with()'s instance from having it swapped underneath them.","triggerScenarios":"Calling setSingletonInstance(picasso) in both Application.onCreate and a test setup; two libraries each installing their own singleton; calling with(context) anywhere first (initializes the default) and then setSingletonInstance.","commonSituations":"Robolectric/JUnit test suites reusing one process where app onCreate runs per test; crash-reporting or leak-canning code re-initializing on relaunch within the same process; migration code adding setSingletonInstance to an app that already called with() eagerly.","solutions":["Call setSingletonInstance exactly once, in Application.onCreate(), before any image load","Wrap test setup: only call it if the singleton is not yet set (guarded by a try/catch or your own initialized flag)","Remove stray with() calls (e.g. in static initializers) that run before your setSingletonInstance","In multi-test processes, prefer building and injecting Picasso instances directly instead of touching the singleton"],"exampleFix":"// before\npublic void onCreate() {\n  super.onCreate();\n  DokitPicasso.setSingletonInstance(defaultPicasso); // crashes on 2nd init\n}\n\n// after\nprivate static boolean picassoInstalled;\npublic void onCreate() {\n  super.onCreate();\n  if (!picassoInstalled) {\n    try {\n      DokitPicasso.setSingletonInstance(defaultPicasso);\n    } catch (IllegalStateException ignored) { /* already installed */ }\n    picassoInstalled = true;\n  }\n}","handlingStrategy":"validation","validationCode":"// Install once, before any with()/load call — typically in Application.onCreate:\npublic class App extends Application {\n  @Override public void onCreate() {\n    super.onCreate();\n    synchronized (DokitPicasso.class) {\n      try {\n        DokitPicasso.setSingletonInstance(\n            new DokitPicasso.Builder(this).build());\n      } catch (IllegalStateException alreadyInstalled) {\n        // second init in the same process (tests, relaunch) — safe to ignore\n      }\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  DokitPicasso.setSingletonInstance(picasso);\n} catch (IllegalStateException e) {\n  if (\"Singleton instance already exists.\".equals(e.getMessage())) {\n    Log.d(TAG, \"Singleton already installed; reusing it\");\n  } else throw e;\n}","preventionTips":["Call setSingletonInstance exactly once, in Application.onCreate, before any load","Ensure no static initializers or early with() calls run first — they lock in the default singleton","In instrumented test suites, prefer injecting Picasso instances over re-installing the singleton"],"tags":["android","picasso","singleton","initialization"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}