[英]Unpredictable behavior when accessing View from another thread
I was trying to build an app which have some thread usage. 我试图构建一个有一些线程使用情况的应用程序。 While working I found unpredictable behavior while I was trying to access a TextView from thread. 在工作时,我尝试从线程访问TextView时发现了无法预测的行为。 I know android forbid us from accessing views directly from another thread.I also know how to access main thread's views from another thread using AsyncTask, Handler , Activity.runOnUiThread(Runnable) , View.post(Runnable) , View.postDelayed(Runnable, long) etc. 我知道android禁止我们直接从另一个线程访问视图。我也知道如何使用AsyncTask,Handler,Activity.runOnUiThread(Runnable),View.post(Runnable),View.post(Runnable),View.postDelayed(Runnable,长)等
Here is my code snippet - 这是我的代码段-
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.tv);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
/*for(int i= 0 ; i<10000000 ;i++){
Log.i("logger"," i ="+i);
tv.setText("i = "+i);
}*/
tv.setText("This is the new text");
}
});
t.start();
}
When I am running this code , no crash occur but as soon as I uncomment Thread.sleep() or for loop part ,crash occur. 当我运行此代码时,不会发生崩溃,但是一旦我取消注释Thread.sleep()或for循环部分,就会发生崩溃。 Can anyone explain this behavior , why it happening like this and why crash is not occurring with given code.Please don't post answers explaining how to do it. 任何人都可以解释这种行为,为什么这样发生以及为什么在给定的代码下不会发生崩溃。请不要发布解释该行为的答案。
Thanks in advance. 提前致谢。
This is the crash log when I uncomment Thread.sleep() code section - 当我取消注释Thread.sleep()代码部分时,这是崩溃日志-
05-26 21:11:47.244: E/AndroidRuntime(14310): FATAL EXCEPTION: Thread-13346
05-26 21:11:47.244: E/AndroidRuntime(14310): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5225)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1062)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:292)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.checkForRelayout(TextView.java:6659)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3670)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3528)
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3503)
05-26 21:11:47.244: E/AndroidRuntime(14310): at com.example.sampleproject.MainActivity$1.run(MainActivity.java:33)
05-26 21:11:47.244: E/AndroidRuntime(14310): at java.lang.Thread.run(Thread.java:864)
05-26 21:11:47.284: D/memalloc(14310): ion: Mapped buffer base:0x5432a000 size:2088960 offset:0 fd:66
Because of a race condition. 由于比赛条件。
Essentially the crash comes when the view tries to invalidate itself in a wrong thread. 本质上,当视图试图使自己在错误的线程中失效时,崩溃就发生了。 setText()
does not invalidate the view unless the view has been measured at least once and the TextView
has a non-null mLayout
. setText()
不会使视图无效,除非已对视图进行了至少一次测量并且TextView
具有非null的mLayout
。
When you create a new view hierarchy with setContentView()
, the message that measures the views is posted on the UI thread's queue but the chances are your thread gets to run before the measure pass has created a layout for the text view. 当使用setContentView()
创建新的视图层次结构时,用于度量视图的消息将发布在UI线程的队列上,但是在度量传递为文本视图创建布局之前,线程有可能运行。
You cannot update UI from another thread, use this instead 您无法从其他线程更新UI,请改用此
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView) findViewById(R.id.tv);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setText("This is the new text");
}
});
}
});
t.start();
}
If you want to know more here a good article: 如果您想在此处了解更多信息,请阅读:
http://android-developers.blogspot.co.uk/2009/05/painless-threading.html http://android-developers.blogspot.co.uk/2009/05/painless-threading.html
Try executing any code that interacts with the UI like this 尝试像这样执行与UI交互的任何代码
runOnUiThread(new Runnable() {
@Override
public void run() {
// Put your UI interactions here
}
});
below code working fine for me: 下面的代码对我来说很好:
public class MainActivity extends Activity {
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle data = msg.getData();
String result=data.getString("key");
textview.setText(result);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final TextView tv = (TextView) findViewById(R.id.tv);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
Bundle bundle=new Bundle();
bundle.putString("key","you data");
Message message=new Message();
message.setData(bundle);
handler.sendMessage(message);
}
});
t.start();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.