在 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中的TextView定义中添加了一行,以便可以识别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/