从另一个线程

时间:2015-05-26 12:03:00

标签: android multithreading android-asynctask

我正在尝试构建一个具有一些线程用法的应用。工作时,我在尝试从线程访问TextView时发现了不可预测的行为。 我知道android禁止我们直接从另一个线程访问视图。我也知道如何使用AsyncTask,Handler,Activity.runOnUiThread(Runnable),View.post(Runnable)从另一个线程访问主线程的视图,View.postDelayed(Runnable,long)等

这是我的代码段 -

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();
    }

当我运行此代码时,不会发生崩溃,但是一旦我取消注释Thread.sleep()或循环部分,就会发生崩溃。 任何人都可以解释这种行为,为什么会发生这种情况以及为什么在给定代码时不会发生崩溃。请不要发布解释如何执行此操作的答案。

提前致谢。

当我取消注释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

4 个答案:

答案 0 :(得分:4)

由于竞争条件。

当视图试图在错误的线程中使自身无效时,崩溃就会发生。 setText()不会使视图无效,除非视图至少被测量过一次且TextView具有非空mLayout

使用setContentView()创建新的视图层次结构时,测量视图的消息将发布在UI线程的队列中,但是在测量传递创建之前,您的线程可能会运行文本视图的布局。

有关详细信息,请查看source

答案 1 :(得分:0)

您无法从其他线程更新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();
}

如果你想在这里了解更多文章:

http://android-developers.blogspot.co.uk/2009/05/painless-threading.html

答案 2 :(得分:0)

尝试执行任何与此UI交互的代码

runOnUiThread(new Runnable() {
  @Override
  public void run() {
      // Put your UI interactions here
  }
});

答案 3 :(得分:0)

以下代码对我来说工作正常:

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();

        }
    }