Android后台服务中RecognitionListener无响应问题如何解决
代码核心问题&修复方案
错误调用识别启动方法
你使用startActivity(mSpeechRecognizerIntent)是启动系统自带的语音识别交互界面,并不会触发你绑定的SttListener回调。使用SpeechRecognizer类实现静默识别时,应该调用mSpeechRecognizer.startListening(mSpeechRecognizerIntent)方法启动识别,删除startActivity相关代码。SpeechRecognizer被GC回收
你将mSpeechRecognizer定义为onStartCommand的局部变量,方法执行完成后该对象会被垃圾回收,后续识别回调没有绑定对象,自然不会触发任何日志。需要将SpeechRecognizer改为Service的全局成员变量。缺少必要权限与前台服务配置
- 语音识别需要
RECORD_AUDIO动态权限,你需要先在Activity中申请该权限后再启动服务,否则识别会直接报错。 - 安卓10及以上版本,后台获取麦克风权限需要申请
FOREGROUND_SERVICE_MICROPHONE权限,同时你的服务必须改为前台服务,在onStartCommand中调用startForeground()绑定通知,否则服务会被系统限制麦克风访问、甚至直接被杀死。 - 你当前
SttListener的onError只输出固定日志,建议打印error code方便定位问题,比如System.out.println("识别错误:" + error),常见错误码可以参考SpeechRecognizer的ERROR_*常量定义。
- 语音识别需要
唤醒词功能逻辑缺失
你当前使用的系统SpeechRecognizer是短语音识别方案,只会在启动后监听一次语音输入,识别完成就会停止,无法实现类似"Hey app"的持续唤醒效果。普通第三方应用无法使用系统级的热词唤醒能力,你需要集成第三方语音SDK的唤醒词功能,比如讯飞语音、百度语音的离线唤醒能力,才能实现后台持续监听唤醒词的效果。
核心修正代码片段
import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.speech.RecognitionListener; import android.speech.RecognizerIntent; import android.speech.SpeechRecognizer; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; import java.util.ArrayList; public class SttService extends Service { // 改为成员变量,避免被GC回收 private SpeechRecognizer mSpeechRecognizer; @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("I am running!"); // 安卓8.0以上必须启动前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("stt_service", "语音识别服务", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); Notification notification = new NotificationCompat.Builder(this, "stt_service") .setContentTitle("语音识别服务运行中") // 替换为你自己应用的图标资源 .setSmallIcon(R.drawable.ic_launcher_foreground) .build(); startForeground(1, notification); } mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this); mSpeechRecognizer.setRecognitionListener(new SttListener()); Intent mSpeechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName()); // 正确启动监听,不要调用startActivity mSpeechRecognizer.startListening(mSpeechRecognizerIntent); return START_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { System.out.println("A sign"); return null; } protected class SttListener implements RecognitionListener { @Override public void onReadyForSpeech(Bundle params) { System.out.println("准备就绪,可以开始说话"); } @Override public void onBeginningOfSpeech() { System.out.println("检测到用户开始说话"); } @Override public void onRmsChanged(float rmsdB) { // 音量变化回调,不需要可以留空 } @Override public void onBufferReceived(byte[] buffer) { } @Override public void onEndOfSpeech() { System.out.println("用户说话结束"); } @Override public void onError(int error) { // 打印错误码方便排查 System.out.println("识别错误,错误码:" + error); } @Override public void onResults(Bundle results) { // 提取识别结果 ArrayList<String> result = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); if (result != null && !result.isEmpty()) { System.out.println("识别结果:" + result.get(0)); } } @Override public void onPartialResults(Bundle partialResults) { } @Override public void onEvent(int eventType, Bundle params) { } } @Override public void onDestroy() { super.onDestroy(); // 销毁时释放SpeechRecognizer资源 if (mSpeechRecognizer != null) { mSpeechRecognizer.destroy(); } } }
额外注意事项
- 必须先在Activity中动态申请
RECORD_AUDIO权限,权限被用户拒绝的情况下识别会直接报错 - 系统自带的SpeechRecognizer在部分厂商ROM中可能被裁剪或者限制后台调用,若遇到兼容性问题建议替换为第三方语音SDK
内容的提问来源于stack exchange,提问作者xRay
相关产品推荐
相关产品推荐

