在前面的浅析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工作原理完全解析,带你从源码的角度彻底理解