{"record":{"id":"f08c327a454a2945","repo":"wasabeef/android-gpuimage","slug":"setrenderer-has-already-been-called-for-this-insta","errorCode":null,"errorMessage":"setRenderer has already been called for this instance.","messagePattern":"setRenderer has already been called for this instance\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"library/src/main/java/jp/co/cyberagent/android/gpuimage/GLTextureView.java","lineNumber":1689,"sourceCode":"                } else {\n                    builder.append(c);\n                }\n            }\n        }\n\n        private void flushBuilder() {\n            if (builder.length() > 0) {\n                Log.v(\"GLTextureView\", builder.toString());\n                builder.delete(0, builder.length());\n            }\n        }\n\n        private StringBuilder builder = new StringBuilder();\n    }\n\n    private void checkRenderThreadState() {\n        if (glThread != null) {\n            throw new IllegalStateException(\"setRenderer has already been called for this instance.\");\n        }\n    }\n\n    private static class GLThreadManager {\n        private static String TAG = \"GLThreadManager\";\n\n        public synchronized void threadExiting(GLThread thread) {\n            if (LOG_THREADS) {\n                Log.i(\"GLThread\", \"exiting tid=\" + thread.getId());\n            }\n            thread.exited = true;\n            if (eglOwner == thread) {\n                eglOwner = null;\n            }\n            notifyAll();\n        }\n\n        /*","sourceCodeStart":1671,"sourceCodeEnd":1707,"githubUrl":"https://github.com/wasabeef/android-gpuimage/blob/ceea576ec931c2968431ad46f1fb2e6d68a542e2/library/src/main/java/jp/co/cyberagent/android/gpuimage/GLTextureView.java#L1671-L1707","documentation":"GLTextureView allows setRenderer() only once per instance; checkRenderThreadState() throws IllegalStateException when the GLThread already exists. Re-attempting initialization (setRenderer/setGLWrapper) on the same view would leak a second render thread, so it is rejected.","triggerScenarios":"Calling setRenderer() a second time on the same GLTextureView — e.g. re-initializing after onConfigurationChanged/orientation change, re-entering a Fragment/Activity lifecycle callback, or a retry path that re-attaches the renderer.","commonSituations":"Fragment views recreated without tearing down state; onAttachedToWindow invoked twice; retrying GPUImage setup after a failure without a new view instance; retaining the old view across config changes.","solutions":["Call setRenderer() exactly once per GLTextureView instance; guard with a boolean flag.","On configuration changes, create a new GPUImage/GPUImageView setup instead of reusing the old view.","Wrap the call: only invoke setRenderer if the renderer has not been installed yet."],"exampleFix":"// before\n gpuImageView.setRenderer(renderer); // may run again on re-attach\n// after\n if (!rendererSet) {\n     gpuImageView.setRenderer(renderer);\n     rendererSet = true;\n }","handlingStrategy":"try-catch","validationCode":"if (rendererAlreadySet) { return; }","typeGuard":null,"tryCatchPattern":"try {\n    gpuImageView.setRenderer(renderer);\n} catch (IllegalStateException e) {\n    // renderer already installed on this instance; safe to ignore or recreate the view\n}","preventionTips":["Set the renderer once, guarded by a boolean (e.g. in a single init method)","Recreate the view on configuration changes instead of re-initializing","Do not call setRenderer from callbacks that can fire multiple times (onAttachedToWindow)"],"tags":["android","gpuimage","opengl","illegal-state","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"ceea576ec931c2968431ad46f1fb2e6d68a542e2","analyzedAt":"2026-09-11T16:56:13.742Z","contentChangedAt":"2026-09-11T16:56:13.742Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}