从源码角度解析View的绘制过程

来源:互联网 发布:淘宝客推广首页 编辑:程序博客网 时间:2024/06/02 06:26

View的绘制过程

下面是View绘制的函数流程

ActivityThread.java

      1. private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason)      2. final void handleResumeActivity(IBinder token,            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason)      3. public final ActivityClientRecord performResumeActivity(IBinder token,            boolean clearHide, String reason)

WindowManagerImpl.java

     4. public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params)

WindowManagerGlobal.java

     5. public void addView(View view, ViewGroup.LayoutParams params,Display display,      Window parentWindow)

ViewRootImpl.java

     6. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView)     7. public void requestLayout()     8. void scheduleTraversals()

Choreographer.java

     9. public void postCallback(int callbackType, Runnable action, Object token)

ViewRootImpl.java

     10. void doTraversal()     11. private void performTraversals()     12. private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,            final Resources res, final int desiredWindowWidth, final int desiredWindowHeight)     13. private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,            boolean insetsPending) throws RemoteException

Session.java

     14. public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,            int requestedWidth, int requestedHeight, int viewFlags,            int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,            Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,            Configuration outConfig, Surface outSurface)

WindowManagerService.java

     15. private int relayoutVisibleWindow(Configuration outConfig, int result, WindowState win,            WindowStateAnimator winAnimator, int attrChanges, int oldVisibility)

ViewRootImpl.java

     16. private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec)

View

     17. public final void measure(int widthMeasureSpec, int heightMeasureSpec)

ViewRootImpl.java

     18. private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,            int desiredWindowHeight)     19. private void performDraw()     20. private void draw(boolean fullRedrawNeeded)

ViewTreeObserver.java

     21. public final void dispatchOnDraw()

ViewRootImpl.java

     22. private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,            boolean scalingRequired, Rect dirty)

Surface.java

     23. public Canvas lockCanvas(Rect inOutDirty)            throws Surface.OutOfResourcesException, IllegalArgumentException     24. private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)            throws OutOfResourcesException

View.java

     25. public void draw(Canvas canvas)     26. private void drawBackground(Canvas canvas)     27. protected void onDraw(Canvas canvas)     28. protected void dispatchDraw(Canvas canvas)     29. public void onDrawForeground(Canvas canvas)     30. private void onDrawScrollIndicators(Canvas c)     31. protected final void onDrawScrollBars(Canvas canvas)

以上便是关于view绘制流程的全部函数流程,下面我再通过解析具体步骤来说一说这个流程的相关操作。

第1步

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {       ···        Activity a = performLaunchActivity(r, customIntent);//通过intent所携带的类名实例化出activity的对象,并将其初始化然后调用完其生命周期中的onCreate()方法        if (a != null) {            r.createdConfig = new Configuration(mConfiguration);            reportSizeConfigurations(r);            Bundle oldState = r.state;            handleResumeActivity(r.token, false, r.isForward,                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);//由这里进入view的绘制过程       ···            } 

第2步

 final void handleResumeActivity(IBinder token,            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {       ···        r = performResumeActivity(token, clearHide, reason);//TAG1        if (r != null) {            final Activity a = r.activity;        ···            boolean willBeVisible = !a.mStartedActivity;            if (!willBeVisible) {                try {                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(                            a.getActivityToken());                } catch (RemoteException e) {                    throw e.rethrowFromSystemServer();                }            }            if (r.window == null && !a.mFinished && willBeVisible) {                r.window = r.activity.getWindow();                View decor = r.window.getDecorView();//这里这个view就是这个activity的根view在activity的onCreate()生命周期中调用setContentView()时初始化,这里不做详细介绍,想了解的同学可以自行查阅源码                decor.setVisibility(View.INVISIBLE);                ViewManager wm = a.getWindowManager();//这个实例其实是一个WindowManagerImpl对象,WindowManager是一个继承自ViewManager的子接口,WindowManagerImpl是这个接口的实现类用于蹭加view到屏幕或者由屏幕移除view                if (a.mVisibleFromClient && !a.mWindowAdded) {                    a.mWindowAdded = true;                    wm.addView(decor, l);//TAG2这里所传入的decor就是之前setContentView时所初始化的View                }            // If the window has already been added, but during resume            // we started another activity, then don't yet make the            // window visible.            } else if (!willBeVisible) {                if (localLOGV) Slog.v(                    TAG, "Launch " + r + " mStartedActivity set");                r.hideForNow = true;            }    }

第3步中看一下上面的TAG1

 public final ActivityClientRecord performResumeActivity(IBinder token,            boolean clearHide, String reason) {        ActivityClientRecord r = mActivities.get(token);        ···        if (r != null && !r.activity.mFinished) {            ···            try {               ···                r.activity.performResume();//在这个方法里面就已经执行调用了activity生命周期中的onStart()和onResume()过程                ···            } catch (Exception e) {               ···            }        }        return r;    }

第4步中看下上面的TAG2

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {        applyDefaultToken(params);        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);//这里的mGlobal对象是处于WindowManagerImpl类中的一个单例成员,且WindowManagerImpl类中的业务逻辑大部分都是通过mGlobal对象的方法来实现的,可以将WindowManagerImpl类理解成为一个框架,mGlobal对象是其具体实现类    }

第8步

void scheduleTraversals() {        if (!mTraversalScheduled) {            mTraversalScheduled = true;            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);//判断是否为立即执行,是的话执行,不是的话等待vsync的回调由队列中取出Runnable进行执行            if (!mUnbufferedInputDispatch) {                scheduleConsumeBatchedInput();            }            notifyRendererOfFramePending();            pokeDrawLockIfNeeded();        }    }final class TraversalRunnable implements Runnable {//这个就是上面中那个Runnable中所实现的方法    @Override    public void run() {        doTraversal();    }}

第11步

private void performTraversals() {        final View host = mView;        ···        if (layoutRequested) {        ···            windowSizeMayChange |= measureHierarchy(host, lp, res,                    desiredWindowWidth, desiredWindowHeight);//测量窗口的大小是否发生改变,函数内部会调用到根view的measure方法        }       ···        final boolean isViewVisible = viewVisibility == View.VISIBLE;        if (mFirst || windowShouldResize || insetsChanged ||                viewVisibilityChanged || params != null || mForceNextWindowRelayout) {            mForceNextWindowRelayout = false;                ···                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);//TAG4                ···            if (mSurfaceHolder != null) {            final ThreadedRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer;            if (hardwareRenderer != null && hardwareRenderer.isEnabled()) {                if (hwInitialized                        || mWidth != hardwareRenderer.getWidth()                        || mHeight != hardwareRenderer.getHeight()                        || mNeedsHwRendererSetup) {                    hardwareRenderer.setup(mWidth, mHeight, mAttachInfo,                            mWindowAttributes.surfaceInsets);                    mNeedsHwRendererSetup = false;                }            }            if (!mStopped || mReportNextDraw) {                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()                        || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||                        updatedConfiguration) {                       ···                         performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);//计算view的大小,会调到跟view的Measure()方法                    ···                }            }        } else {             ···        }        ···        if (didLayout) {            performLayout(lp, mWidth, mHeight);//确定view在界面中的位置           ····        }        ···        if (!cancelDraw && !newSurface) {         ···            performDraw();//TAG5        } else {            ···        }        ···    }

第13步中接上面的TAG4这步里面涉及的类有点多

ViewRootImpl.javaprivate int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,            boolean insetsPending) throws RemoteException {        ···        int relayoutResult = mWindowSession.relayout(                mWindow, mSeq, params,                (int) (mView.getMeasuredWidth() * appScale + 0.5f),                (int) (mView.getMeasuredHeight() * appScale + 0.5f),                viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,                mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,                mSurface);//首先,这个mWindowSession是一个IWindowSession对象,但是我们在源码中并不能搜索到IWindowSession这个类,所以要看mWindowSession.relayout()就得找到他的实现类,所以请往下看      ···    }public ViewRootImpl(Context context, Display display) {        ···        mWindowSession = WindowManagerGlobal.getWindowSession();//在ViewRootImpl构造方法中我们可以看到mWindowSession其实是取自WindowManagerGlobal的所以我们继续往下看       ···    }WindowManagerGlobal.java public static IWindowSession getWindowSession() {        synchronized (WindowManagerGlobal.class) {            if (sWindowSession == null) {                try {                    InputMethodManager imm = InputMethodManager.getInstance();                    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;//这个是sWindowSession对象是通过WindowManagerService的openSession对象得到的        }    }WindowManagerService.javapublic IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,            IInputContext inputContext) {        if (client == null) throw new IllegalArgumentException("null client");        if (inputContext == null) throw new IllegalArgumentException("null inputContext");        Session session = new Session(this, callback, client, inputContext);//在这里我们是终于看到了上面那个mWindowSession的庐山真面目,他其实是一个Session对象,他是一个binder用来连接WindowManagerService与ViewRootImpl之间的通信        return session;    }

第14步

 public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,            int requestedWidth, int requestedHeight, int viewFlags,            int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,            Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,            Configuration outConfig, Surface outSurface) {        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "                + Binder.getCallingPid());        int res = mService.relayoutWindow(this, window, seq, attrs,                requestedWidth, requestedHeight, viewFlags, flags,                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,                outStableInsets, outsets, outBackdropFrame, outConfig, outSurface);//这里调起WindowManagerService的relayoutWindow方法        if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "                + Binder.getCallingPid());        return res;    }

第15步

 public int relayoutWindow(Session session, IWindow client, int seq,            WindowManager.LayoutParams attrs, int requestedWidth,            int requestedHeight, int viewVisibility, int flags,            Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,            Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,            Configuration outConfig, Surface outSurface) {        ···        synchronized(mWindowMap) {            WindowState win = windowForClientLocked(session, client, false);            if (win == null) {                return 0;            }            WindowStateAnimator winAnimator = win.mWinAnimator;            if (viewVisibility != View.GONE) {                win.setRequestedSize(requestedWidth, requestedHeight);//设置系统请求所要设置的高度和宽度            }           ···            if (viewVisibility == View.VISIBLE &&                    (win.mAppToken == null || !win.mAppToken.clientHidden)) {              ···                try {                    result = createSurfaceControl(outSurface, result, win, winAnimator);//当窗口可见时为其创建一个Surface绘图表面                } catch (Exception e) {                  ···                }                ···            } else {               ···            }          ···          //下面这些是返回一些经过计算之后的窗口参数            outFrame.set(win.mCompatFrame);            outOverscanInsets.set(win.mOverscanInsets);            outContentInsets.set(win.mContentInsets);            outVisibleInsets.set(win.mVisibleInsets);            outStableInsets.set(win.mStableInsets);            outOutsets.set(win.mOutsets);            outBackdropFrame.set(win.getBackdropFrame(win.mFrame));           ···        return result;    }

第20步中是接着之前的TAG5

private void draw(boolean fullRedrawNeeded) {        Surface surface = mSurface;       ···        mAttachInfo.mTreeObserver.dispatchOnDraw();//通知所有view的listener要开始绘制了      ···        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {//先判断是否需要重新绘制            if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {//判端硬件加速是否开启                ···                mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);//硬件加速开启的绘制方法            } else {               ···                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {//没开启的绘制方法                    return;                }            }        }        if (animating) {            mFullRedrawNeeded = true;            scheduleTraversals();        }    }

第22步

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,            boolean scalingRequired, Rect dirty) {        // Draw with software renderer.        final Canvas canvas;        try {            canvas = mSurface.lockCanvas(dirty);//获取一片需要绘制区域的画布            canvas.setDensity(mDensity);        } catch (Surface.OutOfResourcesException e) {            ···        } catch (IllegalArgumentException e) {            ···        }        try {            ···            if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {                canvas.drawColor(0, PorterDuff.Mode.CLEAR);//清除这个画布中的所有内容            }            dirty.setEmpty();            mIsAnimating = false;            mView.mPrivateFlags |= View.PFLAG_DRAWN;            if (DEBUG_DRAW) {                Context cxt = mView.getContext();                Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +                        ", metrics=" + cxt.getResources().getDisplayMetrics() +                        ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());            }            try {                canvas.translate(-xoff, -yoff);                if (mTranslator != null) {                    mTranslator.translateCanvas(canvas);                }                canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);                attachInfo.mSetIgnoreDirtyState = false;                mView.draw(canvas);//执行根View的draw方法                drawAccessibilityFocusedDrawableIfNeeded(canvas);            } finally {                ···        } finally {            try {                surface.unlockCanvasAndPost(canvas);//释放这块画布            } catch (IllegalArgumentException e) {               ···            }            ···        }        return true;    }

第25步中,走了这么久终于走到了view的draw方法!!!

public void draw(Canvas canvas) {        ···        /*         * Draw traversal performs several drawing steps which must be executed         * in the appropriate order:         *         *      1. Draw the background         *      2. If necessary, save the canvas' layers to prepare for fading         *      3. Draw view's content         *      4. Draw children         *      5. If necessary, draw the fading edges and restore layers         *      6. Draw decorations (scrollbars for instance)         */        // Step 1, draw the background, if needed        int saveCount;        if (!dirtyOpaque) {            drawBackground(canvas);//先画出背景        }        final int viewFlags = mViewFlags;        boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;        boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;        if (!verticalEdges && !horizontalEdges) {//判断是否能够横向或者纵向的滑动            // Step 3, draw the content            if (!dirtyOpaque) onDraw(canvas);//这是view自己的onDraw方法,用来画出一个view自己的样子            // Step 4, draw the children            dispatchDraw(canvas);//向下分发,让他的子view也去执行draw方法,这样便能将一个根view中所有的view都全部遍历并且绘制完成            // Overlay is part of the content and draws beneath Foreground            if (mOverlay != null && !mOverlay.isEmpty()) {                mOverlay.getOverlayView().dispatchDraw(canvas);            }            // Step 6, draw decorations (foreground, scrollbars)            onDrawForeground(canvas);            // we're done...            return;        }        /*         * Here we do the full fledged routine...         * (this is an uncommon case where speed matters less,         * this is why we repeat some of the tests that have been         * done above)         */        boolean drawTop = false;        boolean drawBottom = false;        boolean drawLeft = false;        boolean drawRight = false;        float topFadeStrength = 0.0f;        float bottomFadeStrength = 0.0f;        float leftFadeStrength = 0.0f;        float rightFadeStrength = 0.0f;        // Step 2, save the canvas' layers        int paddingLeft = mPaddingLeft;        final boolean offsetRequired = isPaddingOffsetRequired();        if (offsetRequired) {            paddingLeft += getLeftPaddingOffset();        }        int left = mScrollX + paddingLeft;        int right = left + mRight - mLeft - mPaddingRight - paddingLeft;        int top = mScrollY + getFadeTop(offsetRequired);        int bottom = top + getFadeHeight(offsetRequired);        if (offsetRequired) {            right += getRightPaddingOffset();            bottom += getBottomPaddingOffset();        }        final ScrollabilityCache scrollabilityCache = mScrollCache;        final float fadeHeight = scrollabilityCache.fadingEdgeLength;        int length = (int) fadeHeight;        // clip the fade length if top and bottom fades overlap        // overlapping fades produce odd-looking artifacts        if (verticalEdges && (top + length > bottom - length)) {            length = (bottom - top) / 2;        }        // also clip horizontal fades if necessary        if (horizontalEdges && (left + length > right - length)) {            length = (right - left) / 2;        }        if (verticalEdges) {            topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));            drawTop = topFadeStrength * fadeHeight > 1.0f;            bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));            drawBottom = bottomFadeStrength * fadeHeight > 1.0f;        }        if (horizontalEdges) {            leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));            drawLeft = leftFadeStrength * fadeHeight > 1.0f;            rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));            drawRight = rightFadeStrength * fadeHeight > 1.0f;        }        saveCount = canvas.getSaveCount();        int solidColor = getSolidColor();        if (solidColor == 0) {            final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;            if (drawTop) {                canvas.saveLayer(left, top, right, top + length, null, flags);            }            if (drawBottom) {                canvas.saveLayer(left, bottom - length, right, bottom, null, flags);            }            if (drawLeft) {                canvas.saveLayer(left, top, left + length, bottom, null, flags);            }            if (drawRight) {                canvas.saveLayer(right - length, top, right, bottom, null, flags);            }        } else {            scrollabilityCache.setFadeColor(solidColor);        }        // Step 3, draw the content        if (!dirtyOpaque) onDraw(canvas);        // Step 4, draw the children        dispatchDraw(canvas);        // Step 5, draw the fade effect and restore layers        final Paint p = scrollabilityCache.paint;        final Matrix matrix = scrollabilityCache.matrix;        final Shader fade = scrollabilityCache.shader;        if (drawTop) {            matrix.setScale(1, fadeHeight * topFadeStrength);            matrix.postTranslate(left, top);            fade.setLocalMatrix(matrix);            p.setShader(fade);            canvas.drawRect(left, top, right, top + length, p);        }        if (drawBottom) {            matrix.setScale(1, fadeHeight * bottomFadeStrength);            matrix.postRotate(180);            matrix.postTranslate(left, bottom);            fade.setLocalMatrix(matrix);            p.setShader(fade);            canvas.drawRect(left, bottom - length, right, bottom, p);        }        if (drawLeft) {            matrix.setScale(1, fadeHeight * leftFadeStrength);            matrix.postRotate(-90);            matrix.postTranslate(left, top);            fade.setLocalMatrix(matrix);            p.setShader(fade);            canvas.drawRect(left, top, left + length, bottom, p);        }        if (drawRight) {            matrix.setScale(1, fadeHeight * rightFadeStrength);            matrix.postRotate(90);            matrix.postTranslate(right, top);            fade.setLocalMatrix(matrix);            p.setShader(fade);            canvas.drawRect(right - length, top, right, bottom, p);        }        canvas.restoreToCount(saveCount);        // Overlay is part of the content and draws beneath Foreground        if (mOverlay != null && !mOverlay.isEmpty()) {            mOverlay.getOverlayView().dispatchDraw(canvas);        }        // Step 6, draw decorations (foreground, scrollbars)        onDrawForeground(canvas);    }

第29步中,如果这个view可以滑动的时候,才会起作用

public void onDrawForeground(Canvas canvas) {        onDrawScrollIndicators(canvas);//画出滑动部分的指示器        onDrawScrollBars(canvas);//画出滑动部分的滑动条        final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;        if (foreground != null) {            if (mForegroundInfo.mBoundsChanged) {                mForegroundInfo.mBoundsChanged = false;                final Rect selfBounds = mForegroundInfo.mSelfBounds;                final Rect overlayBounds = mForegroundInfo.mOverlayBounds;                if (mForegroundInfo.mInsidePadding) {                    selfBounds.set(0, 0, getWidth(), getHeight());                } else {                    selfBounds.set(getPaddingLeft(), getPaddingTop(),                            getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());                }                final int ld = getLayoutDirection();                Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(),                        foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld);                foreground.setBounds(overlayBounds);            }            foreground.draw(canvas);        }    }

到这里,一个view的绘制流程在framework层的工作就结束了,他从activity的启动到一个view的draw全部在上面了,view的从开始计算到绘制都是在activity的onRemuse生命周期之后进行工作的,而且view在绘制的时候是一层一层进行绘制,先绘制父view再在其上进行子view的绘制,Choreographer这个类可以监听到vsync的信号,vsync会每16毫秒发出一次通知,告诉系统该进行屏幕的更新,这样就形成了每秒60帧的刷新率。

阅读全文
0 0
原创粉丝点击