如何在Android应用中实现以Help为触发词的连续语音识别?
Android 连续语音识别监听触发词"Help"问题解决
你的核心问题在于未启动语音识别请求,且未实现识别完成后的重启逻辑,系统SpeechRecognizer默认是单次识别,要实现连续监听需要主动在每次识别结束后重新发起请求。以下是具体修复步骤和代码:
1. 添加必要权限
在AndroidManifest.xml中添加录音权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
2. 动态申请权限(Android 6.0+)
在MainActivity中添加权限检查逻辑,确保应用能获取录音权限:
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... 原有代码 initializeTextToSpeach(); checkAudioPermission(); } private void checkAudioPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_RECORD_AUDIO_PERMISSION); } else { initializeSpeechRecognizer(); startListening(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initializeSpeechRecognizer(); startListening(); } else { Toast.makeText(this, "需要录音权限才能使用语音识别功能", Toast.LENGTH_LONG).show(); finish(); } } }
3. 实现连续监听逻辑
添加启动识别的方法,并在识别完成/出错后重启监听:
private void startListening() { Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.US); // 设置静音超时,避免短静音就结束识别 recognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); recognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 1000); mySpeechRecognizer.startListening(recognizerIntent); } // 修改RecognitionListener的onResults和onError方法 @Override public void onResults(Bundle bundle) { List<String> results = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); if (results != null && !results.isEmpty()) { processResult(results.get(0)); } // 识别完成后重启监听 startListening(); } @Override public void onError(int errorCode) { // 处理常见错误,非致命错误则重启监听 switch (errorCode) { case SpeechRecognizer.ERROR_NO_MATCH: case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: startListening(); break; case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: Toast.makeText(MainActivity.this, "录音权限不足", Toast.LENGTH_SHORT).show(); break; default: Toast.makeText(MainActivity.this, "语音识别错误: " + errorCode, Toast.LENGTH_SHORT).show(); startListening(); } }
4. 优化生命周期管理
在onPause中停止识别,onResume中重启:
@Override protected void onPause() { super.onPause(); myTTS.shutdown(); if (mySpeechRecognizer != null) { mySpeechRecognizer.stopListening(); mySpeechRecognizer.cancel(); } } @Override protected void onResume() { super.onResume(); if (mySpeechRecognizer != null && ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { startListening(); } }
完整修改后代码
public class MainActivity extends AppCompatActivity { private TextToSpeech myTTS; private SpeechRecognizer mySpeechRecognizer; private static final int REQUEST_RECORD_AUDIO_PERMISSION = 100; private AppBarConfiguration appBarConfiguration; private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); setSupportActionBar(binding.toolbar); NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build(); NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration); initializeTextToSpeach(); checkAudioPermission(); } private void checkAudioPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_RECORD_AUDIO_PERMISSION); } else { initializeSpeechRecognizer(); startListening(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initializeSpeechRecognizer(); startListening(); } else { Toast.makeText(this, "需要录音权限才能使用语音识别功能", Toast.LENGTH_LONG).show(); finish(); } } } private void initializeSpeechRecognizer() { if(SpeechRecognizer.isRecognitionAvailable(this)) { mySpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this); mySpeechRecognizer.setRecognitionListener(new RecognitionListener() { @Override public void onReadyForSpeech(Bundle bundle) {} @Override public void onBeginningOfSpeech() {} @Override public void onRmsChanged(float v) {} @Override public void onBufferReceived(byte[] bytes) {} @Override public void onEndOfSpeech() {} @Override public void onError(int errorCode) { switch (errorCode) { case SpeechRecognizer.ERROR_NO_MATCH: case SpeechRecognizer.ERROR_SPEECH_TIMEOUT: startListening(); break; case SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: Toast.makeText(MainActivity.this, "录音权限不足", Toast.LENGTH_SHORT).show(); break; default: Toast.makeText(MainActivity.this, "语音识别错误: " + errorCode, Toast.LENGTH_SHORT).show(); startListening(); } } @Override public void onResults(Bundle bundle) { List<String> results = bundle.getStringArrayList( SpeechRecognizer.RESULTS_RECOGNITION ); if (results != null && !results.isEmpty()) { processResult(results.get(0)); } startListening(); } @Override public void onPartialResults(Bundle bundle) {} @Override public void onEvent(int i, Bundle bundle) {} }); } else { Toast.makeText(this, "设备不支持语音识别", Toast.LENGTH_LONG).show(); finish(); } } private void startListening() { Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.US); recognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, 3000); recognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 1000); mySpeechRecognizer.startListening(recognizerIntent); } private void processResult(String command) { command = command.toLowerCase(); if(command.contains("help")) { Uri number= Uri.parse("tel:123"); Intent intent= new Intent(Intent.ACTION_DIAL, number); startActivity(intent); } } private void initializeTextToSpeach() { myTTS = new TextToSpeech(this, new TextToSpeech.OnInitListener() { @Override public void onInit(int i) { if(myTTS.getEngines().isEmpty()){ Toast.makeText(MainActivity.this, "设备无可用语音引擎", Toast.LENGTH_LONG).show(); finish(); } else { myTTS.setLanguage(Locale.US); speak("Hello, I'm ready"); } } }); } private void speak(String message) { if (Build.VERSION.SDK_INT >= 21) { myTTS.speak(message, TextToSpeech.QUEUE_FLUSH, null, null); } else { myTTS.speak(message, TextToSpeech.QUEUE_FLUSH, null); } } @Override protected void onPause() { super.onPause(); myTTS.shutdown(); if (mySpeechRecognizer != null) { mySpeechRecognizer.stopListening(); mySpeechRecognizer.cancel(); } } @Override protected void onResume() { super.onResume(); if (mySpeechRecognizer != null && ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { startListening(); } } }
关键说明
- 系统
SpeechRecognizer本身没有原生的"唤醒词"持续监听能力,上述方案是通过循环发起识别请求实现近似连续监听,适合简单场景;如果需要更高效的唤醒词检测,建议使用专业语音服务的唤醒词SDK。 - 调整
EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS参数可以控制识别结束的静音时长,可根据需求灵活修改。
内容的提问来源于stack exchange,提问作者ihavenoideawhatimdoing
相关产品推荐
相关产品推荐

