Android:Activity.OnCreate方法中子线程可以更新UI,睡眠后不能更新UI的原因

从源码找答案:
随便找一个UI控件的更新操作,例如TextView的 setText 操作然后追踪:

TextView 类中:

private void setText(CharSequence text, BufferType type,
                         boolean notifyBefore, int oldlen) {
        ...
        if (mLayout != null) {
            checkForRelayout();//调用
        }
        ...
    }
    
    /**
     * 检查全新的文本是否需要新的视图布局
     * 或者只是一个新的文本布局
     */
    private void checkForRelayout() {
    //无论如何都会执行下面两行代码
            ...
            requestLayout();//重新请求布局
            invalidate();//重绘
            ...
    }

最后,invalidate()调用的是View中的invalidate方法

View 类中:

public void invalidate() {// 1
        invalidate(true);
    }
    
    public void invalidate(boolean invalidateCache) {// 2
        invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
    }
    
    void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
            boolean fullInvalidate) {// 3
            ...
            final ViewParent p = mParent;
            if (p != null && ai != null && l < r && t < b) {
                p.invalidateChild(this, damage);
            }
            //调用ViewParent 接口的 invalidateChild方法,该接口被ViewRootImpl实现,
            //并且最终会调用ViewRootImpl的 invalidateChild方法
            //直接去看ViewRootImpl的 invalidateChild方法
            ...
    }
    
    

记住这个 if 条件,条件中 ViewParent 被 ViewRootImpl 实现。并且做了一个判断它不为空程序才会进行下去,因为 mParent 在 Activity 的 onResume 方法中被赋值。所以在onCreate时它是空的。这就是为什么在onCreate 中子线程可以刷新UI的原因。

ViewRootImpl 类中:

    public void invalidateChild(View child, Rect dirty) { // 1
        invalidateChildInParent(null, dirty);
    }
    
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) { // 2
        checkThread();
        ...
    }
    
    void checkThread() { // 3 在这里 判断并抛出异常
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }
    

对,没错,最后的最后,就是在这里 判断并抛出异常的。因为在View中对 ViewParent 实现类有一个判断,当它不为空时才会执行到这里,而 ViewParent 在Activity生命周期的 OnResume 方法中才会被赋值。所以在 onCreate 方法中如果使用子线程是可以做一波更新UI操作的。线程在CPU中调度随机的关系,子线程到这个判断的时候,主线程可能并没有创建ViewParent并赋值。

发布了60 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41466437/article/details/105218834