2013-08-04 5 views
20

Я пытаюсь создать службу для непрерывного распознавания речи в Android 4.2. Используя ответ из этой ссылки (Android Speech Recognition as a service on Android 4.1 & 4.2), я создал службу, которая запускается из Activity. Моя проблема в том, что я получаю null исключения при доступе mTarget.mAudioManager или mTarget.mSpeechRecognizerIntent в методе handleMessage. Объект target (и mTarget), созданный из него, равен , но не null, но все объекты внутри него.Android Speech Recognition Continuous Service

Что я здесь делаю неправильно?

Соответствующая активность Код (статические методы, вызываемые из деятельности, 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(); 
    } 

} 

Service Code:

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<VoiceCommandService> mtarget; 

    IncomingHandler(VoiceCommandService target) 
    { 
     mtarget = new WeakReference<VoiceCommandService>(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; 
} 
} 
+0

Ваш startContinuousListening() точный код у вас есть? –

+0

Да, это так. Я просто разместил код инициализации, который также инициализирует activityContext и службу. Я попытался запустить код в статических методах из самой операции (нестатические методы) с теми же результатами. – rmooney

+0

Как вы определяете voiceCommandService в voiceCommandService.mServerMessenger.send (msg) ;? Это выглядит неправильно, и, вероятно, поэтому ваш код не работает. –

ответ

15

Члены класса в 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; 

} 

Bind служба в 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(); 
} 
+0

Это заставило его работать. Полагаю, мне просто нужно, чтобы сервисное соединение было настроено правильно в этой операции. Большое вам спасибо за вашу помощь! – rmooney

+2

Ваш сервис отлично работает и на Android 4.4. Теперь я хочу перезапустить распознавание речи после вызова onResult(). Я уже пытался отправить сообщение MSG_RECOGNIZER_START_LISTENING или вызвать mSpeechRecognizer.startListening, но он не работает, и я не знаю почему. Я не получаю исключения. Как заставить речевой рекордер перезапускаться после немедленного вызова onResult? – roschulze

+0

У меня нет устройства с 4.4, поэтому я не могу его протестировать. Но попробуйте отправить MSG_RECOGNIZER_CANCEL, а затем MSG_RECOGNIZER_START_LISTENING, чтобы узнать, будет ли это работать. –

Смежные вопросы