Android为什么能在子线程中更新UI

Android为什么能在子线程中更新UI

刚学习Android开发的时候经常有需要在子线程里更新UI的操作,总是会遇到报错:Only the original thread that created a view hierarchy can touch its views.
“只有创建视图层次结构的原始线程才能触摸其视图。”

因为大部分的View创建都是在UI线程(主线程),所以我们都有一个共识:只有在UI线程中才能够更新UI
那为什么呢?

当我们遇到Only the original thread that created a view hierarchy can touch its views. 的时候,可以看到报错的路径是:at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7905)
说明ViewRootImpl这个类对当前线程是否为主线程进行了判断:

@Override
public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
}

void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

ViewRootImlcheckThread方法里,通过判断

mThread != Thread.currentThread()

如果当前没有在UI线程,就会抛出异常


那有没有在子线程中可以更新UI的操作呢?

这里放出一段代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.textView);
        new Thread(new Runnable() {
            @Override
            public void run() {
                tv.setText("子线程更新UI测试");
            }
        }).start();
    }

这样操作是可以改变TextView的Text属性并且没有报错的。
通过上面的了解可以推断,这个时候没有进入ViewRootImplcheckThread方法,逃过一劫,具体原因我们可以从源码入手。这里贴一下讲的很好的链接。

借鉴链接:https://www.jianshu.com/p/58c999d3ada7

结论:从源码分析可得知,ViewRootImpl对象是在onResume方法回调之后才创建,那么就说明了为什么在生命周期的onCreate方法里,甚至是onResume方法里都可以实现子线程更新UI,因为此时还没有创建ViewRootImpl对象,并不会进行是否为主线程的判断;

总结:

  • ViewRootImpl中有checkThread方法,如果当前线程不是UI线程会抛出异常
  • 子线程可以在ViewRootImpl还没有被创建之前更新UI;
  • ViewRootImpl在Activity启动流程中的OnResume()方法被创建
  • 访问UI是没有加对象锁的,在子线程环境下更新UI,会造成不可预期的风险;
  • 开发者更新UI一定要在主线程进行操作;

归根到底这个问题可以从Android的启动流程来分析,Android启动时,先进行OnCreate的回调,然后进行OnResume,这个时候ViewRootImpt还没有进行创建初始化,所以我们在OnCreate中在子线程更新UI是可行的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值