View的重绘

来源:互联网 发布:linux 文件删不掉原因 编辑:程序博客网 时间:2024/05/16 05:32

涉及到view的重绘时,都会涉及到view类的一个函数requestLayout()

public void requestLayout() {        if (mMeasureCache != null) mMeasureCache.clear();        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {            // Only trigger request-during-layout logic if this is the view requesting it,            // not the views in its parent hierarchy            ViewRootImpl viewRoot = getViewRootImpl();            if (viewRoot != null && viewRoot.isInLayout()) {                if (!viewRoot.requestLayoutDuringLayout(this)) {                    return;                }            }            mAttachInfo.mViewRequestingLayout = this;        }        mPrivateFlags |= PFLAG_FORCE_LAYOUT;        mPrivateFlags |= PFLAG_INVALIDATED;        if (mParent != null && !mParent.isLayoutRequested()) {            mParent.requestLayout();        }        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {            mAttachInfo.mViewRequestingLayout = null;        }    }

调用了mParent.requestLayout()(mParent实际上是ViewRootImpl 不熟悉mParent赋值流程的童鞋请先读http://blog.csdn.net/u013866845/article/details/54408825)

 @Override    public void requestLayout() {        if (!mHandlingLayoutInLayoutRequest) {            checkThread();            mLayoutRequested = true;            scheduleTraversals();        }    }
checkThread()函数保证是主线程绘制UI

真正绘制ui的是方法scheduleTraversals

void scheduleTraversals() {        if (!mTraversalScheduled) {            mTraversalScheduled = true;            mTraversalBarrier = mHandler.getLooper().postSyncBarrier();            mChoreographer.postCallback(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);            if (!mUnbufferedInputDispatch) {                scheduleConsumeBatchedInput();            }            notifyRendererOfFramePending();        }    }
把mTraversalRunnable加入队列然后执行

final class TraversalRunnable implements Runnable {        @Override        public void run() {            doTraversal();        }    }
其实是调用了doTraversal()

void doTraversal() {        if (mTraversalScheduled) {            mTraversalScheduled = false;            mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);            if (mProfile) {                Debug.startMethodTracing("ViewAncestor");            }            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");            try {                performTraversals();            } finally {                Trace.traceEnd(Trace.TRACE_TAG_VIEW);            }            if (mProfile) {                Debug.stopMethodTracing();                mProfile = false;            }        }    }
调用了performTraversals()

private void performTraversals()         // cache mView since it is used so much below...        final View host = mView;        if (DBG) {            System.out.println("======================================");            System.out.println("performTraversals");            host.debug();        }                   if (!mStopped) {                boolean focusChangedDueToTouchMode = ensureTouchModeLocally(                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);                if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()                        || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);                    if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed!  mWidth="                            + mWidth + " measuredWidth=" + host.getMeasuredWidth()                            + " mHeight=" + mHeight                            + " measuredHeight=" + host.getMeasuredHeight()                            + " coveredInsetsChanged=" + contentInsetsChanged);                     // Ask host how big it wants to be                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);                    // Implementation of weights from WindowManager.LayoutParams                    // We just grow the dimensions as needed and re-measure if                    // needs be                    int width = host.getMeasuredWidth();                    int height = host.getMeasuredHeight();                    boolean measureAgain = false;                    if (lp.horizontalWeight > 0.0f) {                        width += (int) ((mWidth - width) * lp.horizontalWeight);                        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,                                MeasureSpec.EXACTLY);                        measureAgain = true;                    }                    if (lp.verticalWeight > 0.0f) {                        height += (int) ((mHeight - height) * lp.verticalWeight);                        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,                                MeasureSpec.EXACTLY);                        measureAgain = true;                    }                    if (measureAgain) {                        if (DEBUG_LAYOUT) Log.v(TAG,                                "And hey let's measure once more: width=" + width                                + " height=" + height);                        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);                    }                    layoutRequested = true;                }            }        } else {            ....        }        final boolean didLayout = layoutRequested && !mStopped;        boolean triggerGlobalLayoutListener = didLayout                || mAttachInfo.mRecomputeGlobalAttributes;        if (didLayout) {            performLayout(lp, desiredWindowWidth, desiredWindowHeight);            // By this point all views have been sized and positioned            // We can compute the transparent area            if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {                // start out transparent                // TODO: AVOID THAT CALL BY CACHING THE RESULT?                host.getLocationInWindow(mTmpLocation);                mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],                        mTmpLocation[0] + host.mRight - host.mLeft,                        mTmpLocation[1] + host.mBottom - host.mTop);                host.gatherTransparentRegion(mTransparentRegion);                if (mTranslator != null) {                    mTranslator.translateRegionInWindowToScreen(mTransparentRegion);                }                if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {                    mPreviousTransparentRegion.set(mTransparentRegion);                    mFullRedrawNeeded = true;                    // reconfigure window manager                    try {                        mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);                    } catch (RemoteException e) {                    }                }            }            if (DBG) {                System.out.println("======================================");                System.out.println("performTraversals -- after setFrame");                host.debug();            }        }        if (triggerGlobalLayoutListener) {            mAttachInfo.mRecomputeGlobalAttributes = false;            mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();        }             ....        if (!cancelDraw && !newSurface) {            if (!skipDraw || mReportNextDraw) {                if (mPendingTransitions != null && mPendingTransitions.size() > 0) {                    for (int i = 0; i < mPendingTransitions.size(); ++i) {                        mPendingTransitions.get(i).startChangingAnimations();                    }                    mPendingTransitions.clear();                }                performDraw();            }        } else {            if (viewVisibility == View.VISIBLE) {                // Try again                scheduleTraversals();            } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {                for (int i = 0; i < mPendingTransitions.size(); ++i) {                    mPendingTransitions.get(i).endChangingAnimations();                }                mPendingTransitions.clear();            }        }        mIsInTraversal = false;    }
调用了performMeasure,performLayout,performDraw

private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");        try {            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);        } finally {            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }    }

 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,            int desiredWindowHeight) {        mLayoutRequested = false;        mScrollMayChange = true;        mInLayout = true;        final View host = mView;        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {            Log.v(TAG, "Laying out " + host + " to (" +                    host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");        }        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");        try {            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());            mInLayout = false;            int numViewsRequestingLayout = mLayoutRequesters.size();            if (numViewsRequestingLayout > 0) {                // requestLayout() was called during layout.                // If no layout-request flags are set on the requesting views, there is no problem.                // If some requests are still pending, then we need to clear those flags and do                // a full request/measure/layout pass to handle this situation.                ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,                        false);                if (validLayoutRequesters != null) {                    // Set this flag to indicate that any further requests are happening during                    // the second pass, which may result in posting those requests to the next                    // frame instead                    mHandlingLayoutInLayoutRequest = true;                    // Process fresh layout requests, then measure and layout                    int numValidRequests = validLayoutRequesters.size();                    for (int i = 0; i < numValidRequests; ++i) {                        final View view = validLayoutRequesters.get(i);                        Log.w("View", "requestLayout() improperly called by " + view +                                " during layout: running second layout pass");                        view.requestLayout();                    }                    measureHierarchy(host, lp, mView.getContext().getResources(),                            desiredWindowWidth, desiredWindowHeight);                    mInLayout = true;                    host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());                    mHandlingLayoutInLayoutRequest = false;                    // Check the valid requests again, this time without checking/clearing the                    // layout flags, since requests happening during the second pass get noop'd                    validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true);                    if (validLayoutRequesters != null) {                        final ArrayList<View> finalRequesters = validLayoutRequesters;                        // Post second-pass requests to the next frame                        getRunQueue().post(new Runnable() {                            @Override                            public void run() {                                int numValidRequests = finalRequesters.size();                                for (int i = 0; i < numValidRequests; ++i) {                                    final View view = finalRequesters.get(i);                                    Log.w("View", "requestLayout() improperly called by " + view +                                            " during second layout pass: posting in next frame");                                    view.requestLayout();                                }                            }                        });                    }                }            }        } finally {            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }        mInLayout = false;    }


private void performDraw() {        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {            return;        }        final boolean fullRedrawNeeded = mFullRedrawNeeded;        mFullRedrawNeeded = false;        mIsDrawing = true;        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");        try {            draw(fullRedrawNeeded);        } finally {            mIsDrawing = false;            Trace.traceEnd(Trace.TRACE_TAG_VIEW);        }        // For whatever reason we didn't create a HardwareRenderer, end any        // hardware animations that are now dangling        if (mAttachInfo.mPendingAnimatingRenderNodes != null) {            final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();            for (int i = 0; i < count; i++) {                mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();            }            mAttachInfo.mPendingAnimatingRenderNodes.clear();        }        if (mReportNextDraw) {            mReportNextDraw = false;            if (mAttachInfo.mHardwareRenderer != null) {                mAttachInfo.mHardwareRenderer.fence();            }            if (LOCAL_LOGV) {                Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());            }            if (mSurfaceHolder != null && mSurface.isValid()) {                mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);                SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();                if (callbacks != null) {                    for (SurfaceHolder.Callback c : callbacks) {                        if (c instanceof SurfaceHolder.Callback2) {                            ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(                                    mSurfaceHolder);                        }                    }                }            }            try {                mWindowSession.finishDrawing(mWindow);            } catch (RemoteException e) {            }        }    }
分别调用了view的measure ,layout, draw进行绘制





1 0