From d517b775040c808bde334bd98f089a34699a6beb Mon Sep 17 00:00:00 2001 From: hsangtini Date: Wed, 6 Aug 2025 11:39:18 +0700 Subject: [PATCH 1/2] Fix Android Crash: - FIX 1: Iterate over a copy of the list to avoid ConcurrentModificationException. - FIX 2: Only reply once per request to avoid "Reply already submitted" crash. --- .../tundralabs/fluttertts/FlutterTtsPlugin.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt b/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt index 36fd1421..9a5a1335 100644 --- a/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt +++ b/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt @@ -216,10 +216,11 @@ class FlutterTtsPlugin : MethodCallHandler, FlutterPlugin { private val onInitListenerWithCallback: TextToSpeech.OnInitListener = TextToSpeech.OnInitListener { status -> - // Handle pending method calls (sent while TTS was initializing) + // Safely handle any pending method calls sent while TTS was initializing. synchronized(this@FlutterTtsPlugin) { ttsStatus = status - for (call in pendingMethodCalls) { + // FIX 1: Iterate over a copy of the list to avoid ConcurrentModificationException. + for (call in pendingMethodCalls.toList()) { call.run() } pendingMethodCalls.clear() @@ -238,11 +239,19 @@ class FlutterTtsPlugin : MethodCallHandler, FlutterPlugin { Log.e(tag, "getDefaultLocale: " + e.message) } - engineResult!!.success(1) + // FIX 2: Only reply once per request to avoid "Reply already submitted" crash. + if (engineResult != null) { + engineResult!!.success(1) + engineResult = null // Mark as handled to prevent double-reply. + } } else { - engineResult!!.error("TtsError","Failed to initialize TextToSpeech with status: $status", null) + // FIX 2: Only reply once per request to avoid "Reply already submitted" crash. + if (engineResult != null) { + engineResult!!.error("TtsError","Failed to initialize TextToSpeech with status: $status", null) + engineResult = null // Mark as handled to prevent double-reply. + } } - //engineResult = null + // No need to set engineResult = null here; already handled above. } private val onInitListenerWithoutCallback: TextToSpeech.OnInitListener = From b4f4f4189b7b580a74a0baf6510d9802b1baaabf Mon Sep 17 00:00:00 2001 From: hsangtini Date: Wed, 6 Aug 2025 11:53:44 +0700 Subject: [PATCH 2/2] Fix Android Crash: - FIX 1: Iterate over a copy of the list to avoid ConcurrentModificationException. - FIX 2: Only reply once per request to avoid "Reply already submitted" crash. --- .../kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt b/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt index 9a5a1335..bb01073b 100644 --- a/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt +++ b/android/src/main/kotlin/com/tundralabs/fluttertts/FlutterTtsPlugin.kt @@ -256,10 +256,11 @@ class FlutterTtsPlugin : MethodCallHandler, FlutterPlugin { private val onInitListenerWithoutCallback: TextToSpeech.OnInitListener = TextToSpeech.OnInitListener { status -> - // Handle pending method calls (sent while TTS was initializing) + // Safely handle any pending method calls sent while TTS was initializing. synchronized(this@FlutterTtsPlugin) { ttsStatus = status - for (call in pendingMethodCalls) { + // FIX 1: Iterate over a copy of the list to avoid ConcurrentModificationException. + for (call in pendingMethodCalls.toList()) { call.run() } pendingMethodCalls.clear()