Kotlin中解决SpeechRecognizer需在主线程运行的报错问题
解决SpeechRecognizer必须在主线程运行的问题
问题根源在于UtteranceProgressListener的回调方法(比如onDone)是在后台线程执行的,而Android要求SpeechRecognizer的创建和调用必须在应用主线程,直接调用就会触发报错。
修改方案
只需要把startSTT()的调用切换到主线程即可,有两种简单实现方式:
方式1:使用Service的runOnUiThread方法
因为NotificationListenerService是Service的子类,自带runOnUiThread方法,可以直接用来切换到主线程:
修改UtteranceProgressListener的onDone方法:
tts?.setOnUtteranceProgressListener(object : UtteranceProgressListener() { override fun onDone(utteranceId: String) { // 切换到主线程执行startSTT runOnUiThread { startSTT() } } override fun onError(utteranceId: String) {} override fun onStart(utteranceId: String) {} })
方式2:使用主线程Looper创建Handler
如果需要更灵活的线程切换,可以提前初始化一个绑定主线程的Handler:
- 在Service类中添加Handler实例:
class NotificationListener : NotificationListenerService() { // 绑定主线程Looper的Handler private val mainHandler = Handler(Looper.getMainLooper()) // 其他代码... }
- 在
onDone中通过Handler.post切换线程:
override fun onDone(utteranceId: String) { mainHandler.post { startSTT() } }
修改后的完整代码示例
class NotificationListener : NotificationListenerService() { private val mainHandler = Handler(Looper.getMainLooper()) private var tts: TextToSpeech? = null private fun startSTT() { val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply { putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, packageName) putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault()) } val speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this) speechRecognizer.setRecognitionListener(recognitionListener()) speechRecognizer.startListening(speechRecognizerIntent) } private fun initTextToSpeech() { tts = TextToSpeech(this) { if (it == TextToSpeech.SUCCESS) { val result = tts?.setLanguage(Locale.KOREA) if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { Toast.makeText(this, "language not supported", Toast.LENGTH_SHORT).show() return@TextToSpeech } tts?.setOnUtteranceProgressListener(object : UtteranceProgressListener() { override fun onDone(utteranceId: String) { // 用Handler切换到主线程 mainHandler.post { startSTT() } } override fun onError(utteranceId: String) {} override fun onStart(utteranceId: String) {} }) } } } // 补充实现recognitionListener方法(原代码中未给出) private fun recognitionListener(): RecognitionListener { return object : RecognitionListener { override fun onReadyForSpeech(params: Bundle?) {} override fun onBeginningOfSpeech() {} override fun onRmsChanged(rmsdB: Float) {} override fun onBufferReceived(buffer: ByteArray?) {} override fun onEndOfSpeech() {} override fun onError(error: Int) {} override fun onResults(results: Bundle?) { // 处理识别结果 results?.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)?.let { val recognizedText = it.firstOrNull() // 这里可以把识别到的文本发送为消息 } } override fun onPartialResults(partialResults: Bundle?) {} override fun onEvent(eventType: Int, params: Bundle?) {} } } }
内容的提问来源于stack exchange,提问作者user18560558
相关产品推荐
相关产品推荐

