我们可不可以在子线程中更新UI系列一

本文通过实例演示了在Android中尝试从子线程更新UI的行为。通常情况下,这种操作会导致Onlytheoriginalthreadthatcreatedaviewhierarchycantouchitsviews异常。然而,当UI元素尺寸未变化时,系统可能会允许更新而不抛出异常。一旦涉及尺寸更改,则会触发异常。

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

我们先来看一段代码:


    Button btn;
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        btn=findViewById(R.id.button);
        textView=findViewById(R.id.text);
        btn.setText(Thread.currentThread().getName());
    }
    @Override
    protected void onResume() {
        super.onResume();
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(){
                    @Override
                    public void run() {
                        super.run();

                        try {
                       
                            textView.setText("子线程更新UI"+getName());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }


                    }
                }.start();
            }
        });
    }

 

这段代码是在子线程中更新UI,按理说根据android中View是非线程安全,不可以在子线程更新,如果这样做,应该会抛出一个Only the original thread that created a view hierarchy can touch its views    这样的异常,但是我们跑在模拟器上看一看:

竟然可以绘制出来,并且没有报错,是不是很神奇,那么我们就DEBUG进去看看,我们在

TextView的这个checkForRelayout发现当我们控件高度并没有改变时,android系统并没有去检查线程,而直接去绘制了。这里我摘了这个方法里面的主要代码
..
..
    // Dynamic height, but height has stayed the same,
    // so use our new text layout.
    if (mLayout.getHeight() == oldht
            && (mHintLayout == null || mHintLayout.getHeight() == oldht)) {
        autoSizeText();
        invalidate();
        return;
 // 由于控件的宽度并没有改变,好像并不是网上说的ViewRootImpl这个对象还没创建,在这里已经就绘制了,并且return了
        
    }
}

// We lose: the height has changed and we have a dynamic height.
// Request a new view layout using our new text layout.
requestLayout(); //这里最终调用ViewRootImpl里面的回调方法,并且去检查线程
invalidate();

...

...

}

是不是很神奇,那么我就在子线程中重新设置textView的宽高

LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(300,100);
textView.setLayoutParams(lp);
textView.setText("子线程更新UI"+getName());

所以结果可想而知了,系统给我们抛出了异常

2019-03-26 18:52:29.606 32010-32041/com.example.test E/AndroidRuntime: FATAL EXCEPTION: Thread-4
    Process: com.example.test, PID: 32010
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

所以我们最好还是不要在子线程中更新UI。

参考博客:https://blog.youkuaiyun.com/qq_21937107/article/details/79998194

                  https://blog.youkuaiyun.com/l81372500/article/details/79908139

                  https://blog.youkuaiyun.com/mountain_hua/article/details/81288194

下一篇,我准备整理一下Handler机制和原理,未完待续...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值