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並賦值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章