didi/DoKit · error · IllegalStateException
Singleton instance already exists.
Error message
Singleton instance already exists.
What it means
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.
Source
Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/DokitPicasso.java:678
if (singleton == null) {
synchronized (DokitPicasso.class) {
if (singleton == null) {
singleton = new Builder(context).build();
}
}
}
return singleton;
}
/**
* Set the global instance returned from {@link #with}.
* <p>
* This method must be called before any calls to {@link #with} and may only be called once.
*/
public static void setSingletonInstance(DokitPicasso picasso) {
synchronized (DokitPicasso.class) {
if (singleton != null) {
throw new IllegalStateException("Singleton instance already exists.");
}
singleton = picasso;
}
}
/** Fluent API for creating {@link DokitPicasso} instances. */
@SuppressWarnings("UnusedDeclaration") // Public API.
public static class Builder {
private final Context context;
private Downloader downloader;
private ExecutorService service;
private Cache cache;
private Listener listener;
private RequestTransformer transformer;
private List<RequestHandler> requestHandlers;
private Bitmap.Config defaultBitmapConfig;
private boolean indicatorsEnabled;View on GitHub (pinned to 626827cddb)
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
Example fix
// before
public void onCreate() {
super.onCreate();
DokitPicasso.setSingletonInstance(defaultPicasso); // crashes on 2nd init
}
// after
private static boolean picassoInstalled;
public void onCreate() {
super.onCreate();
if (!picassoInstalled) {
try {
DokitPicasso.setSingletonInstance(defaultPicasso);
} catch (IllegalStateException ignored) { /* already installed */ }
picassoInstalled = true;
}
} Defensive patterns
Strategy: validation
Validate before calling
// Install once, before any with()/load call — typically in Application.onCreate:
public class App extends Application {
@Override public void onCreate() {
super.onCreate();
synchronized (DokitPicasso.class) {
try {
DokitPicasso.setSingletonInstance(
new DokitPicasso.Builder(this).build());
} catch (IllegalStateException alreadyInstalled) {
// second init in the same process (tests, relaunch) — safe to ignore
}
}
}
} Try / catch
try {
DokitPicasso.setSingletonInstance(picasso);
} catch (IllegalStateException e) {
if ("Singleton instance already exists.".equals(e.getMessage())) {
Log.d(TAG, "Singleton already installed; reusing it");
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- buildAndInstall() should only be called once.
- Default singleton instance cannot be shutdown.
- Context must not be null.
- Picasso instance already shut down. Cannot submit new reques
- Cannot set the LeakDirectoryProvider after it has already be
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/5acf6c0a4c49896d.
Report an issue: GitHub.