You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 14:12:57