Skip to content

Android: destroy and recreate the SpeechRecognizer on cancel() - #679

Open
blick wants to merge 1 commit into
csdcorp:mainfrom
blick:fix/android-recreate-recognizer-on-cancel
Open

Android: destroy and recreate the SpeechRecognizer on cancel()#679
blick wants to merge 1 commit into
csdcorp:mainfrom
blick:fix/android-recreate-recognizer-on-cancel

Conversation

@blick

@blick blick commented Sep 5, 2026

Copy link
Copy Markdown

Fixes #678.

cancelListening() now calls destroy() right after cancel() in the same main-thread post and nulls the instance; the next listen() creates a fresh SpeechRecognizer through the existing createRecognizer() path.

Why: cancel() alone leaves the instance's listener registered in the RecognitionService until the service has processed it, and the cancelled session's CANCELLED error still arrives on the plugin's RecognitionListener 25–51 ms later. A listen() started in between treats it as its own error (notifyListening(false) on a live session), after which the following listen() is rejected with error_client ("already in session"). destroy() cancels with isShutdown and detaches the internal listener, so the framework drops the late callback, and a new instance has a new listener binder.

  • Only the cancel path changes; stop() is untouched.
  • The SDK 29 delayed destroyRecognizer() call in cancelListening goes away, since the destroy is now unconditional and synchronous. The stop path keeps it.
  • Recreating the recognizer costs one service bind per listen() after a cancel, ~100 ms on a Pixel 7, which is less than the workaround delays apps use today.

Tested on a Pixel 7 (Android 16, Google recognizer) with an app that restarts recognition between short utterances: cancel → onMicrophoneOpened 82–148 ms per restart, no already in session rejection, no stray error_client/error_busy, no ERROR_RECOGNIZER_BUSY, over 25 restarts at 1.5 s and 0.5 s pacing. Before, with the same script and a 250 ms delay before listen(), 296–404 ms; without the delay, error_client on every restart.

Easy way to see it in the example app: call cancel() and then listen() immediately. On main you get error_client and done; with this change the new session reports listening and delivers results.

@blick
blick force-pushed the fix/android-recreate-recognizer-on-cancel branch from e0ed6a9 to 167e8c5 Compare September 5, 2026 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android: listen() right after cancel()/stop() is rejected or picks up the previous session's callbacks

1 participant