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