Android TextToSpeech初始化阻止/冻结UI线程

时间:2014-07-12 11:50:25

标签: android multithreading user-interface blocking

我写了以下代码:

public class MainActivity extends Activity {

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
   }

   private TextToSpeech mTTS;

   @Override
   protected void onPause() {
       super.onPause();
       if (mTTS != null) {
           mTTS.stop();
           mTTS.shutdown();
       }
   }

   @Override
   protected void onResume() {
       super.onResume();
       mTTS = new TextToSpeech(getApplicationContext(),
               new TextToSpeech.OnInitListener() {
                   @Override
                   public void onInit(int status) {
                       if(status != TextToSpeech.ERROR){
                           mTTS.setLanguage(Locale.ENGLISH);
                           mTTS.speak("Hello!", TextToSpeech.QUEUE_FLUSH, null);
                       }
                   }
               });       
   }

   public void onButtonClick(View view) {
       mTTS.speak("Hello!", TextToSpeech.QUEUE_FLUSH, null);
   }
}

但是这段代码:mTTS = new TextToSpeech(...冻结UI线程5-8秒。

我注意到延迟发生在logcat(第一行)的这一行:

07-13 11:51:11.304    5296-5296/com.example.TextToSpeachTest I/TextToSpeech﹕ Connected to ComponentInfo{com.google.android.tts/com.google.android.tts.service.GoogleTTSService}
07-13 11:51:17.317    5296-5296/com.example.TextToSpeachTest I/Choreographer﹕ Skipped 391 frames!  The application may be doing too much work on its main thread.

我试图把它放在AsyncTask中:

@Override
protected void onResume() {
    super.onResume();

    MyAsyncTask newTask = new MyAsyncTask() {
        protected void onPostExecute(Boolean result) {
        }
    };
    newTask.context = getApplicationContext();
    newTask.execute();
}
...

class MyAsyncTask extends AsyncTask<Void, Integer, Boolean> {
    private TextToSpeech mTTS;
    public Context context;
    @Override
    protected Boolean doInBackground(Void... arg0) {
        mTTS = new TextToSpeech(context,
                new TextToSpeech.OnInitListener() {
                    @Override
                    public void onInit(int status) {
                        if(status != TextToSpeech.ERROR){
                            mTTS.setLanguage(Locale.ENGLISH);
                            mTTS.speak("Hello!", TextToSpeech.QUEUE_FLUSH, null);
                        }
                    }
                });
        return true;
    }
}

但没有改变。你能告诉一个正确的解决方案/想法吗?

此延迟显示在我的手机LG L4 II(E440)上。在Nexus 10上 - 没有延迟。 我在LG L4上尝试了Play商店的不同说话应用程序。在一些应用程序上还有UI阻止,但有些工作没有阻止。这意味着 - 可以实施。但是如何?

2 个答案:

答案 0 :(得分:6)

您的代码没问题,您不需要从其他线程调用TextToSpeech构造函数。

实际上,问题在于使用主UI线程进行语音处理的一些TextToSpeech库的实现。

解决方案是使TextToSpeech处理在一个独立的进程中运行,与UI线程的进程不同。这样,UI交互和语音处理在两个不同进程的主线程中完成。我发现这样做的唯一方法是使用自己的进程在Android服务中创建TextToSpeech对象和控制代码。

要使用自己的流程创建服务, AndroidManifest.xml 中的配置必须包含以下属性: android:process

    <service
        android:name=".TtsService"
        android:enabled="true"
        android:exported="false"
        android:process="com.example.ttsservice">
    </service>

这引入了复杂性,因为现在Activity必须使用Messenger或AIDL(http://developer.android.com/guide/components/bound-services.html)绑定服务来管理TextToSpeech功能。

答案 1 :(得分:0)

你不必在后台线程上发言。

IMO - 你需要实现(TextToSpeech.OnInitListener,UtteranceProgressListener)

                     tts.setOnUtteranceProgressListener(new UtteranceProgressListener()
                     {
                         @Override
                         public void onDone(String utteranceId)
                         {
                             onDoneSpeaking(utteranceId);
                         }

                         @Override
                         public void onError(String utteranceId)
                         {
                         }

                         @Override
                         public void onStart(String utteranceId)
                         {
                         }
                     });
...

    public void onInit(int status) {
        if ( status == TextToSpeech.SUCCESS ) {
            int result = tts.setLanguage( Locale.US );
            if ( result == TextToSpeech.LANG_MISSING_DATA ||
                    result == TextToSpeech.LANG_NOT_SUPPORTED ) {
                Log.e("MainActivity#onInit", "set lang error with "+result);
            }
            else {
                tts.speak(mcomment.substring(left, right), TextToSpeech.QUEUE_FLUSH, null);