java - 从不同线程修改 Android View

标签 java android multithreading

在 Android 上, Activity 在主 UI 线程中运行,而 TextToSpeech 引擎在不同的线程中运行。我想在 TextToSpeech 引擎完成语音回放时更新 Activity 中的 View 。

如果我忽略这一点,那么当 TextToSpeech 引擎调用 Activity 实例时,我会收到 android.view.ViewRoot$CalledFromWrongThreadException 错误。

这是我的代码。错误发生在 MainActivity.java 脚本的最后一行。

TTSUser.java

package com.example.thread;

interface TTSUser {
  void ttsUtteranceComplete();
}

MainActivity.java

package com.example.thread;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity implements TTSUser {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    new TTS(this);
   }

  public void ttsUtteranceComplete() {
    TextView view_to_hide = (TextView) findViewById(R.id.hello_world);

    // On next line: android.view.ViewRoot$CalledFromWrongThreadException:
    // Only the original thread that created a view hierarchy can touch its
    // views.
    view_to_hide.setVisibility(TextView.GONE);
  }
}

TTS.java

package com.example.thread;

import android.app.Activity;
import android.content.Context;
import android.speech.tts.TextToSpeech;

import java.util.HashMap;
import java.util.Locale;

public class TTS implements TextToSpeech.OnInitListener, TextToSpeech.OnUtteranceCompletedListener {

  private final String TAG = "callback";
  private static TextToSpeech tts;
  private TTSUser activity;

  public TTS(TTSUser activity) { // Ensures access to ttsUtteranceComplete()
    this.activity = activity;
    Context context = ((Activity) activity).getApplicationContext();
    tts = new android.speech.tts.TextToSpeech(context, this);
  }

  @Override
  public void onInit(int status) {
    if (status == TextToSpeech.SUCCESS) {
      tts.setLanguage(Locale.UK);
      tts.setOnUtteranceCompletedListener(this);
      speakText("Hello World");
     }
  }

  public void speakText(String toSpeak) {
    int mode = android.speech.tts.TextToSpeech.QUEUE_FLUSH;
   // Create an id for this utterance, so that we can call back when it's done
    HashMap<String, String> hashMap = new HashMap<String, String>();
    hashMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, TAG);

    tts.speak(toSpeak, mode, hashMap);
  }

  public void onUtteranceCompleted(String utteranceID) {
    if (utteranceID.equals(TAG)) {
      activity.ttsUtteranceComplete();
    }
  }
}

我还在activity_main.xml中的T​​extView定义中添加了一行,以便可以识别Hello World文本。

    android:id="@+id/hello_world"

类似措辞问题的其他答案假设另一个线程是在代码中显式创建的。此处,隐式创建 TextToSpeech 引擎的线程。如何更改代码以使 MainActivity.java 的最后一行不会引发错误?

最佳答案

要在 UI 线程外部执行某些操作,您可以使用属于 Activity 的方法 runOnUiThread(Runnable)

所以你可以这样做:

activity.runOnUiThread(new Runnable() { // EDIT: ...Ui... requires a lowercase "i"
  @Override 
  public final void run(){
     // this runs on UI thread
     activity.ttsUtteranceComplete(); // this function will run on the UI thread
  }
});

关于java - 从不同线程修改 Android View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26706342/

相关文章:

java - sleep 线程有时 sleep 时间超过所需时间

java - 如何等待多线程 shell 脚本执行完成在我的 Web 服务中调用?

java - 如何使用上次关闭的设置启动应用程序?

java - Hibernate:与多键表的键之一连接

android - 如何在 Android 中使用 Flurry AddListener 与 Flurry 集成

android - 位图到可以通过异步上传的文件

java - Apache Ignite 中单个分区上的 ScanQuery 是单线程还是多线程?

java - 使用AspectJ监控数据库访问方式

android - Activity 完成得太慢

.net - 多线程中读写隔离