简体   繁体   English

从另一个线程访问View时发生不可预测的行为

[英]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线程的队列上,但是在度量传递为文本视图创建布局之前,线程有可能运行。

For details, examine the source . 有关详细信息,请检查来源

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM