Android语音识别连续服务

我正在尝试创建一个在Android 4.2中运行连续语音识别服务。 使用此链接的答案( Android 4.1和4.2上的Android语音识别作为服务 ),我创建了一个从Activity运行的服务。 我的问题是,在handleMessage方法中访问mTarget.mAudioManagermTarget.mSpeechRecognizerIntent时,我得到nullexception。 目标(以及从中创建的mTarget对象) 不是null ,而是其中的所有对象。

我在这做错了什么?

相关活动代码(从activity调用的静态方法,activityContext是调用此方法的活动):

 public static void init(Context context) { voiceCommandService = new VoiceCommandService(); activityContext = context; } public static void startContinuousListening() { Intent service = new Intent(activityContext, VoiceCommandService.class); activityContext.startService(service); Message msg = new Message(); msg.what = VoiceCommandService.MSG_RECOGNIZER_START_LISTENING; try { voiceCommandService.mServerMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } 

服务代码:

 public class VoiceCommandService extends Service { protected AudioManager mAudioManager; protected SpeechRecognizer mSpeechRecognizer; protected Intent mSpeechRecognizerIntent; protected final Messenger mServerMessenger = new Messenger(new IncomingHandler(this)); protected boolean mIsListening; protected volatile boolean mIsCountDownOn; static final int MSG_RECOGNIZER_START_LISTENING = 1; static final int MSG_RECOGNIZER_CANCEL = 2; @Override public void onCreate() { super.onCreate(); mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this); mSpeechRecognizer.setRecognitionListener(new SpeechRecognitionListener()); 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()); } protected static class IncomingHandler extends Handler { private WeakReference mtarget; IncomingHandler(VoiceCommandService target) { mtarget = new WeakReference(target); } @Override public void handleMessage(Message msg) { final VoiceCommandService target = mtarget.get(); switch (msg.what) { case MSG_RECOGNIZER_START_LISTENING: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { // turn off beep sound target.mAudioManager.setStreamMute(AudioManager.STREAM_SYSTEM, true); } if (!target.mIsListening) { target.mSpeechRecognizer.startListening(target.mSpeechRecognizerIntent); target.mIsListening = true; //Log.d(TAG, "message start listening"); //$NON-NLS-1$ } break; case MSG_RECOGNIZER_CANCEL: target.mSpeechRecognizer.cancel(); target.mIsListening = false; //Log.d(TAG, "message canceled recognizer"); //$NON-NLS-1$ break; } } } // Count down timer for Jelly Bean work around protected CountDownTimer mNoSpeechCountDown = new CountDownTimer(5000, 5000) { @Override public void onTick(long millisUntilFinished) { // TODO Auto-generated method stub } @Override public void onFinish() { mIsCountDownOn = false; Message message = Message.obtain(null, MSG_RECOGNIZER_CANCEL); try { mServerMessenger.send(message); message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING); mServerMessenger.send(message); } catch (RemoteException e) { } } }; @Override public void onDestroy() { super.onDestroy(); if (mIsCountDownOn) { mNoSpeechCountDown.cancel(); } if (mSpeechRecognizer != null) { mSpeechRecognizer.destroy(); } } protected class SpeechRecognitionListener implements RecognitionListener { private static final String TAG = "SpeechRecognitionListener"; @Override public void onBeginningOfSpeech() { // speech input will be processed, so there is no need for count down anymore if (mIsCountDownOn) { mIsCountDownOn = false; mNoSpeechCountDown.cancel(); } //Log.d(TAG, "onBeginingOfSpeech"); //$NON-NLS-1$ } @Override public void onBufferReceived(byte[] buffer) { } @Override public void onEndOfSpeech() { //Log.d(TAG, "onEndOfSpeech"); //$NON-NLS-1$ } @Override public void onError(int error) { if (mIsCountDownOn) { mIsCountDownOn = false; mNoSpeechCountDown.cancel(); } mIsListening = false; Message message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING); try { mServerMessenger.send(message); } catch (RemoteException e) { } //Log.d(TAG, "error = " + error); //$NON-NLS-1$ } @Override public void onEvent(int eventType, Bundle params) { } @Override public void onPartialResults(Bundle partialResults) { } @Override public void onReadyForSpeech(Bundle params) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { mIsCountDownOn = true; mNoSpeechCountDown.start(); mAudioManager.setStreamMute(AudioManager.STREAM_SYSTEM, false); } Log.d(TAG, "onReadyForSpeech"); //$NON-NLS-1$ } @Override public void onResults(Bundle results) { //Log.d(TAG, "onResults"); //$NON-NLS-1$ } @Override public void onRmsChanged(float rmsdB) { } } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } } 

  • 如何查询默认的SpeechRecognizer
  • 哪个Android版本引入了SpeechRecognizer的Audible Cue onReadyForSpeech?
  • 通过“Ok Google”这样的短语开始语音识别?
  • 如何为我的应用创建自定义语音操作?
  • 没有popup的Android语音识别应用程序
  • 在Android上自动下载离线语音识别语言
  • 在Android中使用语音识别的比较:通过Intent还是on-thread?
  • 如何在Android模拟器中启用麦克风输入
  • MainActivity中的类成员

     private int mBindFlag; private Messenger mServiceMessenger; 

    onCreate()启动服务

     @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent service = new Intent(activityContext, VoiceCommandService.class); activityContext.startService(service); mBindFlag = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH ? 0 : Context.BIND_ABOVE_CLIENT; } 

    onStart()绑定服务

     @Override protected void onStart() { super.onStart(); bindService(new Intent(this, VoiceCommandService.class), mServiceConnection, mBindFlag); } @Override protected void onStop() { super.onStop(); if (mServiceMessenger != null) { unbindService(mServiceConnection); mServiceMessenger = null; } } 

    mServiceConnection成员

     private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) {Log.d(TAG, "onServiceConnected");} //$NON-NLS-1$ mServiceMessenger = new Messenger(service); Message msg = new Message(); msg.what = VoiceCommandService.MSG_RECOGNIZER_START_LISTENING; try { mServiceMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { if (DEBUG) {Log.d(TAG, "onServiceDisconnected");} //$NON-NLS-1$ mServiceMessenger = null; } }; // mServiceConnection 

    在服务中

     @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind"); //$NON-NLS-1$ return mServerMessenger.getBinder(); } 

    工作实例如下,

    MyService.class

     public class MyService extends Service implements SpeechDelegate, Speech.stopDueToDelay { public static SpeechDelegate delegate; @Override public int onStartCommand(Intent intent, int flags, int startId) { //TODO do something useful try { if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { ((AudioManager) Objects.requireNonNull( getSystemService(Context.AUDIO_SERVICE))).setStreamMute(AudioManager.STREAM_SYSTEM, true); } } catch (Exception e) { e.printStackTrace(); } Speech.init(this); delegate = this; Speech.getInstance().setListener(this); if (Speech.getInstance().isListening()) { Speech.getInstance().stopListening(); } else { System.setProperty("rx.unsafe-disable", "True"); RxPermissions.getInstance(this).request(permission.RECORD_AUDIO).subscribe(granted -> { if (granted) { // Always true pre-M try { Speech.getInstance().stopTextToSpeech(); Speech.getInstance().startListening(null, this); } catch (SpeechRecognitionNotAvailable exc) { //showSpeechNotSupportedDialog(); } catch (GoogleVoiceTypingDisabledException exc) { //showEnableGoogleVoiceTyping(); } } else { Toast.makeText(this, R.string.permission_required, Toast.LENGTH_LONG).show(); } }); } return Service.START_STICKY; } @Override public IBinder onBind(Intent intent) { //TODO for communication return IBinder implementation return null; } @Override public void onStartOfSpeech() { } @Override public void onSpeechRmsChanged(float value) { } @Override public void onSpeechPartialResults(List results) { for (String partial : results) { Log.d("Result", partial+""); } } @Override public void onSpeechResult(String result) { Log.d("Result", result+""); if (!TextUtils.isEmpty(result)) { Toast.makeText(this, result, Toast.LENGTH_SHORT).show(); } } @Override public void onSpecifiedCommandPronounced(String event) { try { if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { ((AudioManager) Objects.requireNonNull( getSystemService(Context.AUDIO_SERVICE))).setStreamMute(AudioManager.STREAM_SYSTEM, true); } } catch (Exception e) { e.printStackTrace(); } if (Speech.getInstance().isListening()) { Speech.getInstance().stopListening(); } else { RxPermissions.getInstance(this).request(permission.RECORD_AUDIO).subscribe(granted -> { if (granted) { // Always true pre-M try { Speech.getInstance().stopTextToSpeech(); Speech.getInstance().startListening(null, this); } catch (SpeechRecognitionNotAvailable exc) { //showSpeechNotSupportedDialog(); } catch (GoogleVoiceTypingDisabledException exc) { //showEnableGoogleVoiceTyping(); } } else { Toast.makeText(this, R.string.permission_required, Toast.LENGTH_LONG).show(); } }); } } @Override public void onTaskRemoved(Intent rootIntent) { //Restarting the service if it is removed. PendingIntent service = PendingIntent.getService(getApplicationContext(), new Random().nextInt(), new Intent(getApplicationContext(), MyService.class), PendingIntent.FLAG_ONE_SHOT); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); assert alarmManager != null; alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service); super.onTaskRemoved(rootIntent); } } 

    更多细节,

    https://github.com/sachinvarma/Speech-Recognizer

    希望这将有助于将来的某些人。