ListView中requestLayout执行流程解析

在前面的浅析notifyDataSetChanged内部工作流程说到notifyDataSetChanged最终执行的其实是requestLayout方法。

那么requestLayout方法的执行流程是怎样的,它到底做了什么事呢?
另外,我们也执行在setAdapter里面其实也执行了requestLayout这个方法,所以我们知道这个方法对整个ListView的绘制非常重要,其实不仅是ListView,而是所有的View都是如此。
我们先来看看ListView中的setAdapter源码,看看是不是执行了requestLayout方法。

@Override
public void setAdapter(ListAdapter adapter) {
    if (mAdapter != null && mDataSetObserver != null) {
        mAdapter.unregisterDataSetObserver(mDataSetObserver);
    }

    resetList();
    mRecycler.clear();

    if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
        mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
    } else {
        mAdapter = adapter;
    }

    mOldSelectedPosition = INVALID_POSITION;
    mOldSelectedRowId = INVALID_ROW_ID;

    // AbsListView#setAdapter will update choice mode states.
    super.setAdapter(adapter);

    if (mAdapter != null) {
        mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
        mOldItemCount = mItemCount;
        mItemCount = mAdapter.getCount();
        checkFocus();

        mDataSetObserver = new AdapterDataSetObserver();
        mAdapter.registerDataSetObserver(mDataSetObserver);

        mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

        int position;
        if (mStackFromBottom) {
            position = lookForSelectablePosition(mItemCount - 1, false);
        } else {
            position = lookForSelectablePosition(0, true);
        }
        setSelectedPositionInt(position);
        setNextSelectedPositionInt(position);

        if (mItemCount == 0) {
            // Nothing selected
            checkSelectionChanged();
        }
    } else {
        mAreAllItemsSelectable = true;
        checkFocus();
        // Nothing selected
        checkSelectionChanged();
    }

    requestLayout();
}

只需看最后一句就知道,确实有这个方法,接着跟踪看源码:
我们发现ListView没有实现这个方法,所以执行的是它的父类AbsListView类的requestLayout方法:

@Override
public void requestLayout() {
    if (!mBlockLayoutRequests && !mInLayout) {
        super.requestLayout();
    }
}

在这个里面它也没干什么事情,执行了它父类的requestLayout方法。它的父类也没有实现这个方法,最终执行的其实就是View的requestLayout方法。
直接进入源码:

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
    ......
    protected ViewParent mParent;

    AttachInfo mAttachInfo;

    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;
        }
        //设置标志符为PFLAG_FORCE_LAYOUT和PFLAG_INVALIDATED
        //从英文意思就可以知道是进行强制重新布局和重绘
        mPrivateFlags |= PFLAG_FORCE_LAYOUT;
        mPrivateFlags |= PFLAG_INVALIDATED;

        //这里会执行mParent的requestLayout方法
        if (mParent != null && !mParent.isLayoutRequested()) {
            mParent.requestLayout();
        }
        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
            mAttachInfo.mViewRequestingLayout = null;
        }
    }

    ......
}

从上面可以看到最终会执行mParent的requestLayout方法,mParent是一个ViewParent类,它是一个接口,真正的requestLayout实现在它的子类,进入ViewRootImpl源码

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        //确保本次调用的是在UI线程中执行
        checkThread();
        //真正进行布局的代码将检查该变量,并决定是否需要重新布局
        mLayoutRequested = true;
        //发起一个View树遍历的消息,该消息是异步处理的
        //对应的处理函数为performTraversals()
        scheduleTraversals();
    }
}

看看上面的注释,最终执行到了scheduleTraversals方法,接着看源码:

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        scheduleConsumeBatchedInput();
    }
}

我们可以看到它执行了mChoreographer的postCallback方法,mChoreographer是一个Choreographer类。
我们要先说说postCallback里面的mTraversalRunnable参数,它其实是一个TraversalRunnable对象,我们看定义源码:

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

下面进入Choreographer的postCallback函数看看,一步步跟踪,其实最终就是将TraversalRunnable放入到了队列中,最终会执行到mTraversalRunnable的run方法。

public final class Choreographer {

    ......
    public void postCallback(int callbackType, Runnable action, Object token) {
        postCallbackDelayed(callbackType, action, token, 0);
    }

    public void postCallbackDelayed(int callbackType,
            Runnable action, Object token, long delayMillis) {
        if (action == null) {
            throw new IllegalArgumentException("action must not be null");
        }
        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
            throw new IllegalArgumentException("callbackType is invalid");
        }

        postCallbackDelayedInternal(callbackType, action, token, delayMillis);
    }

    private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + delayMillis);
        }

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

}

看看内部源码,在mTraversalRunnable的run方法中,执行了doTraversal()方法,进入到doTraversal方法,我们可以看到执行了performTraversals()方法。

    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            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()的执行过程,可以参看下面两篇博客:
Android中View绘制流程以及invalidate()等相关方法分析

Android视图绘制流程完全解析,带你一步步深入了解View(二)

关于ListView后面的执行过程可以参看下面这篇博客:
Android ListView工作原理完全解析,带你从源码的角度彻底理解

你可能感兴趣的:(源码,android,ListView,执行过程)