天天看點

ViewRootImpl繪制

frameworks/base/core/java/android/view/ViewRootImpl.java

final IWindowSession mWindowSession;
    final W mWindow;
/**
 * The top of a view hierarchy, implementing the needed protocol between View
 * and the WindowManager.  This is for the most part an internal implementation
 * detail of {@link WindowManagerGlobal}.
 *
 * {@hide}
 */
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {

...
    public ViewRootImpl(Context context, Display display) {
...
        mWindowSession = WindowManagerGlobal.getWindowSession();
...
        mWindow = new W(this);
...
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                context);
...
        mChoreographer = Choreographer.getInstance();
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
...
    }
...
}
           

session

Binder

系統中比較常見,表示用戶端與服務端的一次會話。 

WindowManagerGlobal.java
/**
 * Provides low-level communication with the system window manager for
 * operations that are not associated with any particular context.
 *
 * This class is only used internally to implement global functions where
 * the caller already knows the display and relevant compatibility information
 * for the operation.  For most purposes, you should use {@link WindowManager} instead
 * since it is bound to a context.
 *
 * @see WindowManagerImpl
 * @hide
 */ 
   public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
//擷取InputMethodManager單例對象
                    InputMethodManager imm = InputMethodManager.getInstance();
//擷取WindowManagerService的代理對象
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext())
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }
           
static class W extends IWindow.Stub {
        private final WeakReference<ViewRootImpl> mViewAncestor;
        private final IWindowSession mWindowSession;
/*ViewRootImpl内部有一個W類型的對象,它也是基于binder通信,
但是它是用戶端,處理WindowManagerService的請求。
例如按鍵,觸屏事件的通知:

WindowManagerService接收到事件,WindowManagerService找到
UI位于頂層的程序所對應的IWindow對象,
這是一個Bp端,調用這個IWindow對象的dispatchxxx(),
ViewRootImpl的Bn端IWindow接受事件,再派發給相應的處理者。*/

...
...
...
...
   }
           

ViewRootImpl調用performTraversals方法開始周遊整個View樹,執行View的measure,layout,draw流程。View的工作流程就是從performTraversals開始的。其中最核心的就是performTraversals再來看一下其運作調用流程。

scheduleTraversals方法調用地方比較多包含了主要包含了如下:

void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) 

void handleAppVisibility(boolean visible)

void handleGetNewSurface()

public void requestFitSystemWindows() 

//接Activity.attch之後流程之後在WindowManagerGlobal的addView中會執行個體化,
//ViewRootImpl并且執行setView将定義的view設定到裡面
//而ViewRootImpl.setView中有執行requestLayout一次

public void requestLayout() 

void invalidate()

private void invalidateRectOnScreen(Rect dirty)

void setWindowStopped(boolean stopped)

private void profileRendering(boolean enabled)


private void draw(boolean fullRedrawNeeded)

public void requestChildFocus(View child, View focused)

public void clearChildFocus(View child)

public void recomputeViewAttributes(View child) 

public void handleDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args)
           

scheduleTraversals中通過mChoreographer.postCallback一個mTraversalRunnable線程

void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            if (ViewDebugManager.DEBUG_SCHEDULETRAVERSALS) {
                Log.v(mTag, "scheduleTraversals: mTraversalBarrier = " + mTraversalBarrier
                        + ",this = " + this, new Throwable("scheduleTraversals"));
            }
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
           
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
           
final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
           
void doTraversal() {
....
....
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }

}
           

其中就是運作到performTraversals()代碼量比較大,但是核心是三個方法

 1.performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

 2.performLayout(lp, mWidth, mHeight);

3.performDraw();

...
...
            if (!mStopped || mReportNextDraw) {
                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
                        || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
                        updatedConfiguration) {
                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
...
                     // Ask host how big it wants to be
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
...
        if (didLayout) {
...
            performLayout(lp, mWidth, mHeight);
...
        }
...
...
       boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
...
        if (!cancelDraw && !newSurface) {
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).startChangingAnimations();
                }
                mPendingTransitions.clear();
            }

            performDraw();
        }else{
 
            if (isViewVisible) {
                // Try again
                scheduleTraversals();
            } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).endChangingAnimations();
                }
                mPendingTransitions.clear();
            }

        }
           

Activity調用setContentView會調用PhoneWindow的setContentView,最後會調用DecorView的addView方法,這也說明了我們添加的View是DecorView的子元素。

ViewRootImpl繪制

ViewRootImpl中的調用流程基本調用流程:

requestLayout

-->

scheduleTraversals()

-- >

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null)

-->

doTraversal()

-->

performTraversals()

繼續閱讀