SpeechRecognizer方法不在服务中的主线程上

时间:2016-05-01 14:16:35

标签: android service speech-recognition aidl

我正在使用aidl在服务中调用语音识别。识别发生在服务中并将识别传递回应用程序。

问题是startListening方法创建了一个异常:

java.lang.RuntimeException: SpeechRecognizer should be used only from the application's main thread
                                                                               at android.speech.SpeechRecognizer.checkIsCalledFromMainThread(SpeechRecognizer.java:325)
                                                                               at android.speech.SpeechRecognizer.startListening(SpeechRecognizer.java:266)
                                                                               at .InputService$InputBind.speechActivated(InputService.java:79)
                                                                               at .InputBinder$Stub.onTransact(InputBinder.java:50)
                                                                               at android.os.Binder.execTransact(Binder.java:461)

这是我的服务:

public class InputService extends Service implements Actions , Constants {

    private static final int VOICE_MAX_RESULTS = 5;
    private SpeechRecognizer speechRecognizer;
    private static final String TAG = "InputService";
    private InputBind inputBind;

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG , "onBind called");
        if (speechRecognizer == null){
            speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
        }
        speechRecognizer.setRecognitionListener(inputBind);

        inputBind = new InputBind(speechRecognizer);
        return (inputBind);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG , "Service created");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {


        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

    }


    private static class InputBind extends InputBinder.Stub implements RecognitionListener{
        private InputCallback callback;
        private SpeechRecognizer speechRecognizer;
        public InputBind(SpeechRecognizer speechRecognizer){
            this.speechRecognizer = speechRecognizer;
        }
        @Override
        public void speechActivated(InputCallback cb) throws RemoteException {
            callback = cb;
            Intent recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "cmn-Hans-CN");
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "cmn-Hans-HK");
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,"voice.recognition.test");
            recognizerIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, VOICE_MAX_RESULTS);
            speechRecognizer.startListening(recognizerIntent);
        }

        @Override
        public void onReadyForSpeech(Bundle params) {
            try {
                callback.readyForSpeech();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onBeginningOfSpeech() {

        }

        @Override
        public void onRmsChanged(float rmsdB) {

        }

        @Override
        public void onBufferReceived(byte[] buffer) {

        }

        @Override
        public void onEndOfSpeech() {
            try {
                callback.speechEnded();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onError(int error) {
            try {
                callback.speechEnded();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onResults(Bundle results) {
            boolean foundWord = false;
            Log.v(TAG , "onResults Called" );
            ArrayList data =results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
            for (int i = 0; i < data.size(); i++)
            {
                Log.d(TAG, "result " + data.get(i) );
                String result = data.get(i).toString();
                switch (result){
                    case LEFT_ENG:
                    case LEFT_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(LEFT);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case RIGHT_ENG:
                    case RIGHT_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(RIGHT);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case SELECT_ENG:
                    case SELECT_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(SELECT);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case BACK_ENG:
                    case BACK_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(BACK);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case BASKET_ENG:
                    case BASKET_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(BASKET);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                    case EXIT_ENG:
                    case EXIT_CH:
                        foundWord = true;
                        try {
                            callback.onInputReceived(EXIT);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        break;
                }
                if(foundWord)
                    return;
            }
        }

        @Override
        public void onPartialResults(Bundle partialResults) {

        }

        @Override
        public void onEvent(int eventType, Bundle params) {

        }

    }

}

speechActivated是我想要激活语音识别时在主应用程序中调用的方法。 为什么它说我不在主线程上?我还能在哪里调用startListening?

1 个答案:

答案 0 :(得分:0)

该异常足够明显:您必须从Main线程调用此方法。看起来线程效率不高,但这就是API的工作方式。

documentation很清楚:

此类的方法只能从主应用程序线程中调用。