Android CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸视图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3280141/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch views
提问by Donal Rafferty
I have an issue with the following error in Android:
我在 Android 中遇到以下错误的问题:
CalledFromWrongThreadException;: Only the original thread that created a view hierarchy can touch its views
CalledFromWrongThreadException;:只有创建视图层次结构的原始线程才能触及其视图
It appears to happen when I try to update a Textview in my Activity, the call to update the TextView is from within my Activity but I still get the above error.
当我尝试在我的 Activity 中更新 Textview 时,似乎会发生这种情况,更新 TextView 的调用来自我的 Activity 但我仍然收到上述错误。
I have it like this:
我有这样的:
onCreate() -sets up the buttons and the text view.
onCreate() - 设置按钮和文本视图。
onStateChange() - a listener for notifications about state changes, when this gets notification if changes the TextView to say some different text.
onStateChange() - 状态更改通知的侦听器,如果将 TextView 更改为某些不同的文本,则会收到通知。
When I get notification of a new text I try to change the TextView as so:
当我收到新文本的通知时,我尝试将 TextView 更改为:
((TextView)findViewById(R.id.title)).setText("Some Text");
But I get the above Error.
但我得到了上述错误。
From googling it, it appears I should use a handler to change the TextView or maybe use AsyncTask?
通过谷歌搜索,看来我应该使用处理程序来更改 TextView 或者使用 AsyncTask?
Could anyone explain which one would be better to use and why?
谁能解释一下哪个更好用,为什么?
EDIT: ADDED CODE SNIPPETS:
编辑:添加代码片段:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.my);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.my_title);
((TextView)findViewById(R.id.time)).setText("Hello Text");
findViewById(R.id.keyboardimage).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:"));
startActivity(dialIntent);
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.FLAG_SOFT_KEYBOARD));
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
}
});
}
//CallBacks from running Service
private final ICallDialogActivity.Stub iCallDialogActivity = new ICallDialogActivity.Stub(){
@Override
public void onStateChanged(int callState)
throws RemoteException {
switch(callState){
case GlobalData.CALL_STATUS_IDLE:
break;
case GlobalData.CALL_STATUS_DISCONNECTING:
byeSetup();
break;
}
};
public void byeSetup(){
((TextView)findViewById(R.id.time)).setText("Bye Text");
findViewById(R.id.keyboardimage).setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//Void the Button
}});
}
回答by willcodejavaforfood
Look like you are on the wrong thread. Try using a Handler to update the GUI on the right thread. See Handling Expensive Operations in the UI Threadexample from android.com. Basically you would wrap byeSetup
in a Runnable
and invoke it with a Handler
instance.
看起来你走错了线程。尝试使用处理程序在正确的线程上更新 GUI。请参阅处理来自 android.com的 UI 线程示例中的昂贵操作。基本上你会用byeSetup
a包装Runnable
并用一个Handler
实例调用它。
Handler refresh = new Handler(Looper.getMainLooper());
refresh.post(new Runnable() {
public void run()
{
byeSetup();
}
});
回答by Keshav Gera
when the change involves to the main thread (UiThread). Use it inside of another Thread to changes any view.
当更改涉及到主线程 ( UiThread) 时。在另一个线程中使用它来更改任何视图。
runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO your Code
et_Pass.setText("");
}
});
回答by Kevin
Expanding on willcodejavaforfood's answer for clarity & implementation...
为清晰和实施扩展 willcodejavaforfood 的答案......
I got this to work and below is how I did it. I'm running multiple processing threads in a Service so other solutions that run in Activity don't work, like runOnUiThread(new Runnable() {}...
我让这个工作,下面是我是怎么做的。我在一个 Service 中运行多个处理线程,因此在 Activity 中运行的其他解决方案不起作用,例如 runOnUiThread(new Runnable() {}...
Put this at the top of your service class so it's accessible everywhere in this class:
把它放在你的服务类的顶部,这样它就可以在这个类的任何地方访问:
Handler handler;
Put this in your service class onCreate method or something that loads on Service main thread
把它放在你的服务类 onCreate 方法或在服务主线程上加载的东西
handler= new Handler(Looper.getMainLooper());
Put this inside your additional thread to 'post back' code to get run in UI or service UI (whatevers its called):
将它放在您的附加线程中以“回发”代码以在 UI 或服务 UI 中运行(无论它叫什么):
handler.post(new Runnable() {
public void run() {
playNext(); //or whatever method you want to call thats currently not working
}
});
回答by Joseph Selvaraj
For others, just replace byeSetup(); with your code statements or methods. byeSetup() is a sample method. Hope it will save some of your time.
对于其他人,只需替换 byeSetup(); 使用您的代码语句或方法。byeSetup() 是一个示例方法。希望它可以节省您的一些时间。
回答by Jaroslav Záruba
Another approach, this time making use of android.os.Message
另一种方法,这次利用 android.os.Message
Have android.os.Handler
defined as a field within your activity:
已android.os.Handler
定义为您活动中的字段:
private final Handler myTextHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message stringMessage) {
textView.append((String) stringMessage.obj);
return true;
}
});
Then feed it from your other thread like this:
然后像这样从你的另一个线程中输入它:
Message stringMessage = Message.obtain(myTextHandler);
stringMessage.obj = "Hello!";
stringMessage.sendToTarget();
回答by Nero
You can use view's inbuilt post method to update contents in other thread like I'm using edit text in kotlin.
您可以使用视图的内置 post 方法来更新其他线程中的内容,就像我在 kotlin 中使用编辑文本一样。
address_box.post { address_box.text="my text"}