今天一位朋友问了我一个问题,android更新ui的时候,如果不在主线程更新ui,系统就会报出错误,应用崩溃
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
基于此,简读了一下View ViewRootImpl 的源码。
总得来说android 在UI线程创建UI元素,并把线程的引用存储到UI控件中,。在更新UI之前检测下当前线程是否跟创建自己的线程是同一个线程。
每个View持有一个viewParent的引用。ViewParent 是一个接口,ViewGroup ViewRootImpl 都实现了这个接口。
protected ViewParent mParent;
public interface ViewParent{
...
public void invalidateChild(View child,Rect r);
public ViewParent invalidateChildInParent(int[]location,Rect r);
...
}
更新View invalidate的时候,会最终调用到ViewGroup的invalidateChild
最终调用ViewRootImpl的invalidateChidInParent方法
如果View在invalidate之前调用了requestLayout方法,那么这个之后,viewRootImpl的requestLayout,就会调用checkThread来检测,此方法就是检测创建自己的线程跟更新自己的线程是否是同一个线程。
如ImageView在setImageResource的时候,判断,如果新的resource 的width和height跟old都相同,就不会调用requestLayout,这个时候会在invalidate的时候进行检查。而在setScaleType的时候,只要跟原scaleType不一致,就会requestLayout,这个时候,在requestLayout的时候就会被检测到。
如TextView在setText的时候会调用checkForRelayout,方法会调用requestLayout
网友评论