didi/DoKit · error · IllegalStateException

Listener already set.

Error message

Listener already set.

What it means

DokitPicasso.Builder.listener() throws IllegalStateException when a Listener has already been set. The listener slot is single-assignment like the other builder components, so configuring it twice fails immediately.

Solutions

  1. Register only one Listener and route events from it to all consumers
  2. If multiple observers are needed, create a composite listener that fans out and register it once
  3. Remove the duplicate listener() call

Example fix

// before
builder.listener(baseListener);
builder.listener(appListener); // IllegalStateException

// after
class CompositeListener implements DokitPicasso.Listener {
  ...delegate to baseListener and appListener...
}
builder.listener(new CompositeListener());
Defensive patterns

Strategy: validation

Validate before calling

class Composite implements DokitPicasso.Listener { public void onImageLoadFailed(DokitPicasso p, Uri u, Exception e) { a.onImageLoadFailed(p,u,e); b.onImageLoadFailed(p,u,e); } }
builder.listener(new Composite()); // registered once

Try / catch

try { builder.listener(l); } catch (IllegalStateException e) { if (!e.getMessage().contains("Listener already set")) throw e; }

Prevention

When it happens

Trigger: Calling builder.listener(...) twice, e.g. a base SDK init installs a listener and app code installs another one for its own error reporting.

Common situations: Layered initialization (framework + app) that both want load-failure callbacks; merging two setup code paths without deduplicating the listener call.

Related errors


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/56c9d7b4a4c306f5. Report an issue: GitHub.

Appendix: source

Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/DokitPicasso.java:765

    /** Specify the memory cache used for the most recent images. */
    public Builder memoryCache(Cache memoryCache) {
      if (memoryCache == null) {
        throw new IllegalArgumentException("Memory cache must not be null.");
      }
      if (this.cache != null) {
        throw new IllegalStateException("Memory cache already set.");
      }
      this.cache = memoryCache;
      return this;
    }

    /** Specify a listener for interesting events. */
    public Builder listener(Listener listener) {
      if (listener == null) {
        throw new IllegalArgumentException("Listener must not be null.");
      }
      if (this.listener != null) {
        throw new IllegalStateException("Listener already set.");
      }
      this.listener = listener;
      return this;
    }

    /**
     * Specify a transformer for all incoming requests.
     * <p>
     * <b>NOTE:</b> This is a beta feature. The API is subject to change in a backwards incompatible
     * way at any time.
     */
    public Builder requestTransformer(RequestTransformer transformer) {
      if (transformer == null) {
        throw new IllegalArgumentException("Transformer must not be null.");
      }
      if (this.transformer != null) {
        throw new IllegalStateException("Transformer already set.");
      }

View on GitHub (pinned to 626827cddb)