Android: destroy and recreate the SpeechRecognizer on cancel() - #679
Open
blick wants to merge 1 commit into
Open
Android: destroy and recreate the SpeechRecognizer on cancel()#679blick wants to merge 1 commit into
blick wants to merge 1 commit into
Conversation
blick
force-pushed
the
fix/android-recreate-recognizer-on-cancel
branch
from
September 5, 2026 11:41
d524bca to
e0ed6a9
Compare
blick
force-pushed
the
fix/android-recreate-recognizer-on-cancel
branch
from
September 5, 2026 11:47
e0ed6a9 to
167e8c5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #678.
cancelListening()now callsdestroy()right aftercancel()in the same main-thread post and nulls the instance; the nextlisten()creates a freshSpeechRecognizerthrough the existingcreateRecognizer()path.Why:
cancel()alone leaves the instance's listener registered in theRecognitionServiceuntil the service has processed it, and the cancelled session'sCANCELLEDerror still arrives on the plugin'sRecognitionListener25–51 ms later. Alisten()started in between treats it as its own error (notifyListening(false)on a live session), after which the followinglisten()is rejected witherror_client("already in session").destroy()cancels withisShutdownand detaches the internal listener, so the framework drops the late callback, and a new instance has a new listener binder.stop()is untouched.destroyRecognizer()call incancelListeninggoes away, since the destroy is now unconditional and synchronous. The stop path keeps it.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 →
onMicrophoneOpened82–148 ms per restart, noalready in sessionrejection, no strayerror_client/error_busy, noERROR_RECOGNIZER_BUSY, over 25 restarts at 1.5 s and 0.5 s pacing. Before, with the same script and a 250 ms delay beforelisten(), 296–404 ms; without the delay,error_clienton every restart.Easy way to see it in the example app: call
cancel()and thenlisten()immediately. Onmainyou geterror_clientanddone; with this change the new session reportslisteningand delivers results.