{"record":{"id":"56c9d7b4a4c306f5","repo":"didi/DoKit","slug":"listener-already-set","errorCode":null,"errorMessage":"Listener already set.","messagePattern":"Listener already set\\.","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/DokitPicasso.java","lineNumber":765,"sourceCode":"    /** Specify the memory cache used for the most recent images. */\n    public Builder memoryCache(Cache memoryCache) {\n      if (memoryCache == null) {\n        throw new IllegalArgumentException(\"Memory cache must not be null.\");\n      }\n      if (this.cache != null) {\n        throw new IllegalStateException(\"Memory cache already set.\");\n      }\n      this.cache = memoryCache;\n      return this;\n    }\n\n    /** Specify a listener for interesting events. */\n    public Builder listener(Listener listener) {\n      if (listener == null) {\n        throw new IllegalArgumentException(\"Listener must not be null.\");\n      }\n      if (this.listener != null) {\n        throw new IllegalStateException(\"Listener already set.\");\n      }\n      this.listener = listener;\n      return this;\n    }\n\n    /**\n     * Specify a transformer for all incoming requests.\n     * <p>\n     * <b>NOTE:</b> This is a beta feature. The API is subject to change in a backwards incompatible\n     * way at any time.\n     */\n    public Builder requestTransformer(RequestTransformer transformer) {\n      if (transformer == null) {\n        throw new IllegalArgumentException(\"Transformer must not be null.\");\n      }\n      if (this.transformer != null) {\n        throw new IllegalStateException(\"Transformer already set.\");\n      }","sourceCodeStart":747,"sourceCodeEnd":783,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/DokitPicasso.java#L747-L783","documentation":"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.","triggerScenarios":"Calling builder.listener(...) twice, e.g. a base SDK init installs a listener and app code installs another one for its own error reporting.","commonSituations":"Layered initialization (framework + app) that both want load-failure callbacks; merging two setup code paths without deduplicating the listener call.","solutions":["Register only one Listener and route events from it to all consumers","If multiple observers are needed, create a composite listener that fans out and register it once","Remove the duplicate listener() call"],"exampleFix":"// before\nbuilder.listener(baseListener);\nbuilder.listener(appListener); // IllegalStateException\n\n// after\nclass CompositeListener implements DokitPicasso.Listener {\n  ...delegate to baseListener and appListener...\n}\nbuilder.listener(new CompositeListener());","handlingStrategy":"validation","validationCode":"class Composite implements DokitPicasso.Listener { public void onImageLoadFailed(DokitPicasso p, Uri u, Exception e) { a.onImageLoadFailed(p,u,e); b.onImageLoadFailed(p,u,e); } }\nbuilder.listener(new Composite()); // registered once","typeGuard":null,"tryCatchPattern":"try { builder.listener(l); } catch (IllegalStateException e) { if (!e.getMessage().contains(\"Listener already set\")) throw e; }","preventionTips":["Use one composite listener when multiple subsystems need failure callbacks"],"tags":["android","picasso","builder","configuration"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}