android - 为什么我在尝试从非 ui 线程更改 UI View 组件时没有得到预期的 CalledFromWrongThreadException

标签 android multithreading

作为 android 编程的初学者,我被教导不能从非 ui 线程更改 UI View 组件,但在下面的简单代码 fragment 中似乎可以完成(非 ui 线程更改按钮文本,这是由 UI 线程创建)...我已经完成研究,我应该得到 CalledFromWrongThreadException。请帮忙?

public class MainActivity extends AppCompatActivity {

    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.button);
    }

    public void clickDo(View view){
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();
    }

    class MyRunnable implements Runnable{
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            button.setText("newText"); //<-------- here?
        }
    }
}

最佳答案

当您调用 TextView.setText() 时,会发生很多事情。修改正在显示的文本的实际操作是独立于检查 View 布局是否需要更改的操作,更改布局是唯一需要在 UI 上完成的操作线程。

setText()的源代码中,有这么一点点:

if (mLayout != null) {
    checkForRelayout();
}

不同于the previously-linked duplicate ,我们知道 mLayout 在这种情况下是非空的。所以我们知道正在调用 checkForRelayout()

但是,查看 checkForRelayout() 表明,在某些情况下,该方法在不调用 requestLayout() 和/或 invalidate()< 的情况下返回。在这些情况下(未调用 requestLayout()),不会抛出预期的 CalledFromWrongThreadException

本质上,如果 TextView 具有固定宽度,并且新文本的行数与旧文本的行数相同,则不会调用 requestLayout()

这意味着您可以从非 UI 线程自由调用 setText() 只要您知道 TextView 具有固定宽度并且新的和旧文本具有相同的行数。


我做了一些实验来验证这一点。事实上,当我的 Button 使用 wrap_content 宽度时,我总是会遇到您的代码崩溃。但是,当我将其更改为 match_parent 时,我只会在新文本换行到第二行时发生崩溃。

关于android - 为什么我在尝试从非 ui 线程更改 UI View 组件时没有得到预期的 CalledFromWrongThreadException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53122802/

相关文章:

java - 抽屉导航中的 3 行图标未动画化为较小的图像

java - 每秒检查一次时间

java - 在受控对象中更新的实体未在作业中更新

ruby Watir : cannot launch browser in a thread in Linux

java - SMSManager 和国家/地区代码前缀

android - 如何在不堆叠行的情况下更改奇数行的 backgroundTint?

android - 如何在 React Native 中将 TextInput 中的输入大写?我无法通过 TextField 的 autoCapitalize 属性将句子、单词或字符大写

python - DAG的并行处理

c++ - 在 C++ 线程之间共享数据容器的最佳方式是什么

android - android中的自定义条形图 View