一个奇怪的子线程更新UI问题

本文解析了在Android应用中如何正确地从子线程更新UI元素,特别是TextView的更新过程,并对比了Toast的工作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final TextView tv = (TextView) findViewById(R.id.tv);
    Log.d(TAG, "run0: " + Thread.currentThread().getId());
    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "run1: " + Thread.currentThread().getId());
            Looper.prepare();
            Handler handler = new Handler();
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Log.d(TAG, "run2: " + Thread.currentThread().getId());
                    tv.setText("错误");
                }
            });
            Looper.loop();
        }
    }).start();
}

}

tv正确执行了更新
输出结果是:

03-02 10:32:18.932 13244-13244/com.kyle.myapplication D/MainActivity: run0: 1
03-02 10:32:18.942 13244-14758/com.kyle.myapplication D/MainActivity: run: 408
03-02 10:32:18.942 13244-14758/com.kyle.myapplication D/MainActivity: run2: 408

感谢[@赵凯强]给出的解答(http://blog.youkuaiyun.com/zhaokaiqiang1992/article/details/43410351)

虽然是在子线程中setText,但是这时候View还没画出来呢,所以并不会调用之后的invalidate,而相当于只是设置TextView的一个属性,不会invalidate,就没有后面的那些方法调用了,归根结底,就不会调用ViewRootImpl的checkThread,也就不会报错

还有补充

Toast和View本质上是不一样的,Toast的显示是系统服务回调TN.show()显示的,Toast的显示需要添加到一个MessageQueue中,然后Looper取出来,发给Handler调用显示,子线程因为没有Looper,所以需要加上Looper.prepare和Looper.loop创建一个Looper,但是实质上,这还是在子线程调用。本质上Toast并不涉及到子线程更新UI的操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值