{"record":{"id":"863f8e0c8073777f","repo":"Justson/AgentWeb","slug":"the-jscallback-isn-t-permanent-cannot-be-called-mo","errorCode":null,"errorMessage":"the JsCallback isn't permanent,cannot be called more than once","messagePattern":"the JsCallback isn't permanent,cannot be called more than once","errorType":"exception","errorClass":"JsCallbackException","httpStatus":null,"severity":"error","filePath":"agentweb-core/src/main/java/com/just/agentweb/JsCallback.java","lineNumber":54,"sourceCode":"\n    public JsCallback(WebView view, String injectedName, int index) {\n        mCouldGoOn = true;\n        mWebViewRef = new WeakReference<WebView>(view);\n        mInjectedName = injectedName;\n        mIndex = index;\n    }\n\n    /**\n     * 向网页执行js回调；\n     * @param args\n     * @throws JsCallbackException\n     */\n    public void apply (Object... args) throws JsCallbackException {\n        if (mWebViewRef.get() == null) {\n            throw new JsCallbackException(\"the WebView related to the JsCallback has been recycled\");\n        }\n        if (!mCouldGoOn) {\n            throw new JsCallbackException(\"the JsCallback isn't permanent,cannot be called more than once\");\n        }\n        StringBuilder sb = new StringBuilder();\n        for (Object arg : args){\n            sb.append(\",\");\n            boolean isStrArg = arg instanceof String;\n            // 有的接口将Json对象转换成了String返回，这里不能加双引号，否则网页会认为是String而不是JavaScript对象；\n            boolean isObjArg = isJavaScriptObject(arg);\n            if (isStrArg && !isObjArg) {\n                sb.append(\"\\\"\");\n            }\n            sb.append(String.valueOf(arg));\n            if (isStrArg && !isObjArg) {\n                sb.append(\"\\\"\");\n            }\n        }\n        String execJs = String.format(CALLBACK_JS_FORMAT, mInjectedName, mIndex, mIsPermanent, sb.toString());\n        if (LogUtils.isDebug()) {\n            Log.d(\"JsCallBack\", execJs);","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/Justson/AgentWeb/blob/8f7f6adbf01010e9b2b44638f31edf10e1ba53f7/agentweb-core/src/main/java/com/just/agentweb/JsCallback.java#L36-L72","documentation":"JsCallback.apply throws JsCallbackException when the callback is not permanent (mCouldGoOn == false) and apply() is called a second time. Non-permanent callbacks are single-use: the first apply() already ended the JS call chain (invoking the native completion on the JS side).","triggerScenarios":"Calling apply() twice on the same JsCallback returned for a one-shot JS native method (any callback not marked permanent), or retrying apply() after a failed first invocation.","commonSituations":"Looping over results and calling apply per item with a one-shot callback (should use permanentCallback + call() semantics instead), retry logic that re-invokes apply on exception, or duplicated event delivery calling the same callback twice.","solutions":["Call apply() at most once per JsCallback; pass all data in that single invocation","For multiple invocations use the permanent-callback API (permanentCallback()/call()) so mCouldGoOn stays true","Track a boolean 'called' flag around the callback usage","Catch JsCallbackException on repeat calls and log instead of crashing"],"exampleFix":"// before\nfor (Item it : items) { callback.apply(it); } // second apply throws\n// after\ncallback.permanentCallback();\nfor (Item it : items) { callback.call(it); }","handlingStrategy":"try-catch","validationCode":"if (!firstCall) { return; } // guard one-shot callback with a flag","typeGuard":null,"tryCatchPattern":"try { callback.apply(result); } catch (JsCallbackException e) { Log.w(TAG, \"one-shot callback reused\", e); }","preventionTips":["Call apply() exactly once per JsCallback","Use permanentCallback() for repeated calls","Deduplicate events before invoking callbacks","Never retry apply() on failure with the same instance"],"tags":["android","javascript-bridge","js-callback","single-use"],"backgroundTag":"unsupported-operation","analyzedSha":"8f7f6adbf01010e9b2b44638f31edf10e1ba53f7","analyzedAt":"2026-09-11T10:05:24.337Z","contentChangedAt":"2026-09-11T10:05:24.337Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}