首先我们看下TextView
的源码,如下图所示:
在
TextView
的源码中可以找到在执行setText()
方法时一定会执行requestLayout()
和invalidate()
方法,而在requestLayout()
中代码如下图所示:image.png
ViewRootImpl viewRoot = getViewRootImpl();
获取的ViewRootImpl
类是ViewParent
接口的实现类image.png
而
ViewParent
接口中有requestLayout()
方法需要实现,如下图所示:image.png
这时后再看图二中红框标注的
mParent.requestLayout()
就会发现mParent
其实就是一个viewParent
接口具体实现类的对象也就是ViewRootImpl
类image.png
再看
ViewRootImpl
中requestLayout()
的具体实现如下图所示:image.png
想必到了这里大家看到
checkThread()
就已经猜到了子线程不能更新ui的异常是怎么抛出的,还是看下具体的代码:image.png
到了这里大家就会有疑问了,那为什么子线程
setText()
没有异常呢,那是因为如果你图一中的 invalidate()
方法是线程第一行代码执行而requestLayout()
检查线程是个耗时操作,invalidate()
方法快于requestLayout()
检查到线程异常就不会报错。出自古龙小李飞刀的天下武功,唯快不破!放在代码中同样适用,想要验证这个结论你可以在setText()
之前Thread.sleep(1000)
让线程休眠1s试一下,你就会发现本来正常的代码突然抛出异常了!
网友评论