ListView中requestLayout执行流程解析
2015-08-14 19:31
441 查看
在前面的浅析notifyDataSetChanged内部工作流程说到notifyDataSetChanged最终执行的其实是requestLayout方法。
那么requestLayout方法的执行流程是怎样的,它到底做了什么事呢?
另外,我们也执行在setAdapter里面其实也执行了requestLayout这个方法,所以我们知道这个方法对整个ListView的绘制非常重要,其实不仅是ListView,而是所有的View都是如此。
我们先来看看ListView中的setAdapter源码,看看是不是执行了requestLayout方法。
只需看最后一句就知道,确实有这个方法,接着跟踪看源码:
我们发现ListView没有实现这个方法,所以执行的是它的父类AbsListView类的requestLayout方法:
在这个里面它也没干什么事情,执行了它父类的requestLayout方法。它的父类也没有实现这个方法,最终执行的其实就是View的requestLayout方法。
直接进入源码:
从上面可以看到最终会执行mParent的requestLayout方法,mParent是一个ViewParent类,它是一个接口,真正的requestLayout实现在它的子类,进入ViewRootImpl源码
看看上面的注释,最终执行到了scheduleTraversals方法,接着看源码:
我们可以看到它执行了mChoreographer的postCallback方法,mChoreographer是一个Choreographer类。
我们要先说说postCallback里面的mTraversalRunnable参数,它其实是一个TraversalRunnable对象,我们看定义源码:
下面进入Choreographer的postCallback函数看看,一步步跟踪,其实最终就是将TraversalRunnable放入到了队列中,最终会执行到mTraversalRunnable的run方法。
看看内部源码,在mTraversalRunnable的run方法中,执行了doTraversal()方法,进入到doTraversal方法,我们可以看到执行了performTraversals()方法。
后面performTraversals()的执行过程,可以参看下面两篇博客:
Android中View绘制流程以及invalidate()等相关方法分析
Android视图绘制流程完全解析,带你一步步深入了解View(二)
关于ListView后面的执行过程可以参看下面这篇博客:
Android ListView工作原理完全解析,带你从源码的角度彻底理解
那么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_TR***ERSAL, 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工作原理完全解析,带你从源码的角度彻底理解
相关文章推荐
- OC - NSValueAndNSNumber
- UIView如何管理它的子视图
- IOS UIGraphicsBeginImageContext 使用简介
- iOS arc与非arc混编 以及设置UINavigationBar的高度
- UI-父视图和子视图之间的关系
- ios UISlider总结
- Django1.8:403错误:CSRF verification failed. Request aborted.
- 在AWS上为1.25亿用户实现移动应用个性化
- UINavigationController小知识点
- DNS服务器性能测试(基于queryperf)
- iOS UIView的setNeedsLayout, layoutIfNeeded 和 layoutSubviews 方法之间的关系解释
- 【UVa 540】Team Queue
- iOS 归档UIImageView后,再解档,imageview的图片出现自动旋转
- Codeforces Round #250 D - The Child and Sequence/[TYVJ3838] DQS和序列(by 帝江&Darkfalmes)
- iOS基础-UIKit框架-多控制器管理-Segue
- Codeforces Gym 100379I Move the queen to the corner! 威佐夫博弈变形 + 高精度
- HDU 4106 Fruit Ninja 费用流
- A simple Test-Query Program
- EasyUI中tree,Datagrid,pagenation的使用EasyUI中Datagrid和pagenation进行关联时,再次点击pagenation时让表格数据显示的问题
- EasyUI中tree,Datagrid,pagenation的使用EasyUI中Datagrid和pagenation进行关联时,再次点击pagenation时让表格数据显示的问题