作为 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/