Android可不可以在子线程中更新UI?

5个月前 (12-09) 0 点赞 0 收藏 0 评论 8 已阅读

我们首先来看一段代码:

在一个activity的xml文件中随便写一个TextView文本控件,然后在Activity的onCreate方法中开启一个子线程并在该子线程的run方法中更新TextView文本控件,你会发现根本没有任何问题。

但是如果你把Thread.sleep(2000)放开绘发现报错崩溃:

我们从这堆栈开始分析源码原因:

mButton.setText("woyaoniu");会调用android.widget.TextView#checkForRelayout方法中来,checkForRelayout继续调用android.view.View#requestLayout这里来:

我们来mParent是什么,首先它是一个ViewParent接口,requestLayout()是接口中定义的一个方法:

但是完整实现类却在View中,而不是ViewGroup中 虽然是ViewGroup实现了ViewParent接口

接着我们去看下View中mParent的来历:

View中的mParent成员变量通常来说指的就是当前View的父容器ViewGroup,但有一个特殊就是,对于顶层decorView来说它的mParent是ViewRootImpl。下面我们看源码来证实:

mParent通过方法assignParent(ViewParent parent)被赋值:

1 在ViewRootImpl中的setView方法中设置传递过来的DecorView,在该方法中会给DecorView中的mParent指定为当前ViewRootImpl,而且ViewRootImpl实现了ViewParent接口。

2 将View添加到ViewGroup中,通常使用addView(View child)等方法,最后会调用内部的addViewInner方法,将添加进来的子View的mParent设置为当前所在容器:

那么从调用android.view.View#requestLayout一直往上调用,最后会执行到ViewRootImpl#requestLayout方法

至此这个调用分析链报错就可以到这了。下面再看为啥注释掉Thread.sleep(2000)就没有报错呢:

根本原因就是ViewRootImpl到底是在哪初始化的呢!ViewRootImpl是在onResume中初始化的,而我们开启的子线程是在onCreate中,这个时候程序还没有去检测当前线程是不是主线程,所以就没有抛异常,下面我们去看ActivityThread源码,找出原因:


Android可不可以在子线程中更新UI?

本文收录在
0评论

登录

忘记密码 ?

切换登录

注册