【问题标题】:Android Error: Only the original thread that created a view hierarchy can touch its views [duplicate]Android错误:只有创建视图层次结构的原始线程才能触摸其视图[重复]
【发布时间】:2013-06-15 03:02:28
【问题描述】:

出现错误:android.view.ViewRootImpl$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能接触其视图。
我真的不知道为什么。

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button generate = (Button) findViewById(R.id.gen);
    final TextView dice1 = (TextView) findViewById(R.id.dice1);
    final TextView dice2 = (TextView) findViewById(R.id.dice2);
    final TextView dice3 = (TextView) findViewById(R.id.dice3);


    generate.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {           
            dice1.setText(" ");
            dice2.setText(" ");
            dice3.setText(" ");         
            Thread thread = new Thread()
            {
                @Override
                public void run() {
                    try {
                        while(true) {
                            sleep(2000);
                            setText("lol", "lol", "lol");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            thread.start();             
        }

    });
}
public void setText(String d1, String d2, String d3){
    dice1.setText(d1);
    dice2.setText(d2);
    dice3.setText(d3);  
}

感谢您的帮助。

【问题讨论】:

    标签: android multithreading text


    【解决方案1】:

    您遇到此错误是因为您在 UI 线程之外的另一个线程中操作视图。 你的setText方法修改了3个TextView的文本(dice1dice2dice3)。

    你应该像这样用runOnUiThread 调用这个方法:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button generate = (Button) findViewById(R.id.gen);
        final TextView dice1 = (TextView) findViewById(R.id.dice1);
        final TextView dice2 = (TextView) findViewById(R.id.dice2);
        final TextView dice3 = (TextView) findViewById(R.id.dice3);
    
        generate.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {           
                dice1.setText(" ");
                dice2.setText(" ");
                dice3.setText(" ");         
                Thread thread = new Thread()
                {
                    @Override
                    public void run() {
                        try {
                            while(true) {
                                sleep(2000);
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        setText("lol", "lol", "lol");
                                    }
                                });
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                thread.start();             
            }
    
        });
    }
    public void setText(String d1, String d2, String d3){
        dice1.setText(d1);
        dice2.setText(d2);
        dice3.setText(d3);  
    }
    

    【讨论】:

    • 在线程内睡眠是一个糟糕的设计。 developer.android.com/training/articles/perf-anr.html
    • @Raghunandan 如果您在主线程上调用 sleep() 是的,但在这种情况下不是。但是,可以肯定的是,例如使用AsynTask 可能比每次用户单击“生成”按钮时创建一个线程要好...
    • 如果你实现了Thread or HandlerThread,确保你的UI线程在等待工作线程完成时不会阻塞——do not call Thread.wait() or Thread.sleep()。引用自文档。
    • 是的,意思是“不要在UI线程上调用Thread.wait()等待另一个线程调用Thread.notify() i> 例如。在 UI 线程之外的另一个线程上调用 Thread.sleep()(或 Thread.wait())不会导致 ANR。
    • 它阻塞了工作线程。所以不好。我不是说它会导致anr。
    【解决方案2】:

    从字面上看,您是在尝试从错误的线程中设置视图中的字段。您的 OnClickListener 会创建一个新线程,但只有创建视图及其层次结构的线程才能更改这些视图。

    你可以重构使用http://developer.android.com/reference/java/util/concurrent/ScheduledThreadPoolExecutor.html

    或者,您可以将 setter 代码包装在 runOnUiThread 块内。此站点上有一个示例,并提醒您为什么这可能不是一个好主意:Android: RunOnUiThread vs AsyncTask

    【讨论】:

      【解决方案3】:

      您将 setText 设置在一个单独的线程上。将调用操作 UI 组件的方法放在 runOnUiThread 块中。

      【讨论】:

        猜你喜欢
        • 2017-07-15
        • 1970-01-01
        • 2016-01-17
        • 1970-01-01
        • 2015-05-22
        • 2013-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多