ListView 能局部刷新吗?
可以。。。

和ListView 的区别? 强在哪里?
更加灵活

怎么布局的? 怎么就实现了可以列表 和 网格的切换?

是怎样的回收和重复利用View?

不管recycleView 是何方神圣,最终都会调用到onMeasure、onLayout

androidx.recyclerview.widget.LinearLayoutManager#fill

RecycleView 缓存机制

1.从mAttachedScrap 里面获取
mAttachedScrap 好像没有被使用
真的没有看到这个的作用在哪里。好像没有用。

2.mCachedViews 获取
用于存放最常用的3个,包括将要显示的那个,预加载的,以及刚回收的
GapWorker 预创建View 完成之后就会放到cached 里面

"main"@12,125 in group "main": RUNNING
recycleViewHolderInternal(RecyclerView$ViewHolder):6487, RecyclerView$Recycler {androidx.recyclerview.widget}, RecyclerView.java
recycleView(View):6369, RecyclerView$Recycler {androidx.recyclerview.widget}, RecyclerView.java
prefetchPositionWithDeadline(RecyclerView, int, long):295, GapWorker {androidx.recyclerview.widget}, GapWorker.java
flushTaskWithDeadline(GapWorker$Task, long):345, GapWorker {androidx.recyclerview.widget}, GapWorker.java
flushTasksWithDeadline(long):361, GapWorker {androidx.recyclerview.widget}, GapWorker.java
prefetch(long):368, GapWorker {androidx.recyclerview.widget}, GapWorker.java
run():399, GapWorker {androidx.recyclerview.widget}, GapWorker.java
handleCallback(Message):873, Handler {android.os}, Handler.java
dispatchMessage(Message):99, Handler {android.os}, Handler.java
loop():193, Looper {android.os}, Looper.java

3.mRecyclerPool 获取
用于存在每一种类型的,5个。和CacheView 作用不太一样。

4.ViewCacheExtension获取

为什么做这么多层级的缓存?意义在哪里?
难道是这一层级的,不需要绑定数据?可以直接用?

5.GapWorker 到底是干什么用的? 怎么干的?

6.绑定ViewHolder之后什么时候添加到View树上的?

androidx.recyclerview.widget.LinearLayoutManager#layoutChunk

里面会调用addView

7.怎么实现的?滑动就增加view? 怎么实现这么流畅的?
onMeasure,onLayout 不会调用吗?(不会)
为什么?

父容器RecycleView 是不会重新调用onMeasure,onLayout的,但是会调用item 的 onMeasure 和 on Layout.

androidx.recyclerview.widget.LinearLayoutManager#layoutChunk
但是不调用invalidate 会刷新吗?
他不会去刷新layout。

8.requestLayout 和 invalidate 什么区别? 分别什么时候调用比较好?
invalidate 会导致重新布局吗?
requestLayout 会导致 onDraw 调用吗?
//invalidate 不会重新onLayout onMeasure
// invalidate();
// 重新布局 onMeasure onLayout onDraw 都会重新调用
requestLayout();
9.view 怎么 移动的 ? 肯定不是scroll, 应该是调用layout方法。

offsetTopAndBottom(int):15964, View {android.view}, View.java
offsetChildrenVertical(int):5042, RecyclerView {androidx.recyclerview.widget}, RecyclerView.java
offsetChildrenVertical(int):9136, RecyclerView$LayoutManager {androidx.recyclerview.widget}, RecyclerView.java
offsetChildren(int):369, OrientationHelper$2 {androidx.recyclerview.widget}, OrientationHelper.java
scrollBy(int, RecyclerView$Recycler, RecyclerView$State):1399, LinearLayoutManager {androidx.recyclerview.widget}, LinearLayoutManager.java
scrollVerticallyBy(int, RecyclerView$Recycler, RecyclerView$State):1128, LinearLayoutManager {androidx.recyclerview.widget}, LinearLayoutManager.java
scrollStep(int, int, int[]):1841, RecyclerView {androidx.recyclerview.widget}, RecyclerView.java
scrollByInternal(int, int, MotionEvent):1940, RecyclerView {androidx.recyclerview.widget}, RecyclerView.java

调用的offsetTopAndBottom 实现移动。调用requestLayout 其实会更改mTop 的,但是recycleView 没有问题是因为重写了onMeasure 方法,不会重新给mTop赋值。

10.offsetTopAndBottom 有什么优点?有什么作用?
快速移动? 不需要重新布局?只移动自己,不需要麻烦parent.

11.ainamator是怎么实现的?

12.具体的recycleView 的机制是什么?会提前加载上下一个列表项目吗?

13.滑动的时候,是先回收view还是先创建view 添加到底部?
首先,回收view, 然后添加下面的view,最后再回收view.

androidx.recyclerview.widget.RecyclerView#scrollBy

fill(RecyclerView$Recycler, LinearLayoutManager$LayoutState, RecyclerView$State, boolean):1576, LinearLayoutManager {androidx.recyclerview.widget}, LinearLayoutManager.java
scrollBy(int, RecyclerView$Recycler, RecyclerView$State):1391, LinearLayoutManager {androidx.recyclerview.widget}, LinearLayoutManager.java
scrollVerticallyBy(int, RecyclerView$Recycler, RecyclerView$State):1128, LinearLayoutManager {androidx.recyclerview.widget}, LinearLayoutManager.java
scrollStep(int, int, int[]):1841, RecyclerView {androidx.recyclerview.widget}, RecyclerView.java
scrollByInternal(int, int, MotionEvent):1940, RecyclerView {androidx.recyclerview.widget}, RecyclerView.java
onTouchEvent(MotionEvent):3391, RecyclerView {androidx.recyclerview.widget}, RecyclerView.java
    static class LayoutState {static final String TAG = "LLM#LayoutState";static final int LAYOUT_START = -1;static final int LAYOUT_END = 1;static final int INVALID_LAYOUT = Integer.MIN_VALUE;static final int ITEM_DIRECTION_HEAD = -1;static final int ITEM_DIRECTION_TAIL = 1;static final int SCROLLING_OFFSET_NaN = Integer.MIN_VALUE;/*** We may not want to recycle children in some cases (e.g. layout)*/boolean mRecycle = true;/*** Pixel offset where layout should start* 应该接着哪里布局,接着那里添加view*/int mOffset;/*** Number of pixels that we should fill, in the layout direction.* 当前需要填充的长度* 可以为负数 如果是负数 说明滑动的距离 不足够划出下一个展示的View*/int mAvailable;/*** Current position on the adapter to get the next item.*/int mCurrentPosition;/*** Defines the direction in which the data adapter is traversed.* Should be {@link #ITEM_DIRECTION_HEAD} or {@link #ITEM_DIRECTION_TAIL}*/int mItemDirection;/*** Defines the direction in which the layout is filled.* Should be {@link #LAYOUT_START} or {@link #LAYOUT_END}*/int mLayoutDirection;/*** Used when LayoutState is constructed in a scrolling state.* It should be set the amount of scrolling we can make without creating a new view.* Settings this is required for efficient view recycling.* 滚动多少范围内,不需要创建新的view*/int mScrollingOffset;/*** Used if you want to pre-layout items that are not yet visible.* The difference with {@link #mAvailable} is that, when recycling, distance laid out for* {@link #mExtraFillSpace} is not considered to avoid recycling visible children.*/int mExtraFillSpace = 0;/*** Contains the {@link #calculateExtraLayoutSpace(RecyclerView.State, int[])}  extra layout* space} that should be excluded for recycling when cleaning up the tail of the list during* a smooth scroll.*/int mNoRecycleSpace = 0;/*** Equal to {@link RecyclerView.State#isPreLayout()}. When consuming scrap, if this value* is set to true, we skip removed views since they should not be laid out in post layout* step.*/boolean mIsPreLayout = false;/*** The most recent {@link #scrollBy(int, RecyclerView.Recycler, RecyclerView.State)}* amount.*/int mLastScrollDelta;/*** When LLM needs to layout particular views, it sets this list in which case, LayoutState* will only return views from this list and return null if it cannot find an item.*/List<RecyclerView.ViewHolder> mScrapList = null;/*** Used when there is no limit in how many views can be laid out.*/boolean mInfinite;/*** @return true if there are more items in the data adapter*/boolean hasMore(RecyclerView.State state) {return mCurrentPosition >= 0 && mCurrentPosition < state.getItemCount();}/*** Gets the view for the next element that we should layout.* Also updates current item index to the next item, based on {@link #mItemDirection}** @return The next element that we should layout.*/View next(RecyclerView.Recycler recycler) {if (mScrapList != null) {return nextViewFromScrapList();}final View view = recycler.getViewForPosition(mCurrentPosition);mCurrentPosition += mItemDirection;return view;}/*** Returns the next item from the scrap list.* <p>* Upon finding a valid VH, sets current item position to VH.itemPosition + mItemDirection** @return View if an item in the current position or direction exists if not null.*/private View nextViewFromScrapList() {final int size = mScrapList.size();for (int i = 0; i < size; i++) {final View view = mScrapList.get(i).itemView;final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();if (lp.isItemRemoved()) {continue;}if (mCurrentPosition == lp.getViewLayoutPosition()) {assignPositionFromScrapList(view);return view;}}return null;}public void assignPositionFromScrapList() {assignPositionFromScrapList(null);}public void assignPositionFromScrapList(View ignore) {final View closest = nextViewInLimitedList(ignore);if (closest == null) {mCurrentPosition = RecyclerView.NO_POSITION;} else {mCurrentPosition = ((RecyclerView.LayoutParams) closest.getLayoutParams()).getViewLayoutPosition();}}public View nextViewInLimitedList(View ignore) {int size = mScrapList.size();View closest = null;int closestDistance = Integer.MAX_VALUE;if (DEBUG && mIsPreLayout) {throw new IllegalStateException("Scrap list cannot be used in pre layout");}for (int i = 0; i < size; i++) {View view = mScrapList.get(i).itemView;final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();if (view == ignore || lp.isItemRemoved()) {continue;}final int distance = (lp.getViewLayoutPosition() - mCurrentPosition)* mItemDirection;if (distance < 0) {continue; // item is not in current direction}if (distance < closestDistance) {closest = view;closestDistance = distance;if (distance == 0) {break;}}}return closest;}void log() {Log.d(TAG, "avail:" + mAvailable + ", ind:" + mCurrentPosition + ", dir:"+ mItemDirection + ", offset:" + mOffset + ", layoutDir:" + mLayoutDirection);}}
    /*** The magic functions :). Fills the given layout, defined by the layoutState. This is fairly* independent from the rest of the {@link LinearLayoutManager}* and with little change, can be made publicly available as a helper class.** @param recycler        Current recycler that is attached to RecyclerView* @param layoutState     Configuration on how we should fill out the available space.* @param state           Context passed by the RecyclerView to control scroll steps.* @param stopOnFocusable If true, filling stops in the first focusable new child* @return Number of pixels that it added. Useful for scroll functions.*/int fill(RecyclerView.Recycler recycler, LayoutState layoutState,RecyclerView.State state, boolean stopOnFocusable) {// max offset we should set is mFastScroll + available//记录最开始的时候  可用的空间final int start = layoutState.mAvailable;if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {// TODO ugly bug fix. should not happenif (layoutState.mAvailable < 0) {//如果可用空间小于0  那么mScrollingOffset 就减去这个数layoutState.mScrollingOffset += layoutState.mAvailable;}recycleByLayoutState(recycler, layoutState);}int remainingSpace = layoutState.mAvailable + layoutState.mExtraFillSpace;LayoutChunkResult layoutChunkResult = mLayoutChunkResult;while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {layoutChunkResult.resetInternal();if (RecyclerView.VERBOSE_TRACING) {TraceCompat.beginSection("LLM LayoutChunk");}layoutChunk(recycler, state, layoutState, layoutChunkResult);if (RecyclerView.VERBOSE_TRACING) {TraceCompat.endSection();}if (layoutChunkResult.mFinished) {break;}layoutState.mOffset += layoutChunkResult.mConsumed * layoutState.mLayoutDirection;/*** Consume the available space if:* * layoutChunk did not request to be ignored* * OR we are laying out scrap children* * OR we are not doing pre-layout*/if (!layoutChunkResult.mIgnoreConsumed || layoutState.mScrapList != null|| !state.isPreLayout()) {layoutState.mAvailable -= layoutChunkResult.mConsumed;// we keep a separate remaining space because mAvailable is important for recyclingremainingSpace -= layoutChunkResult.mConsumed;}if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {layoutState.mScrollingOffset += layoutChunkResult.mConsumed;if (layoutState.mAvailable < 0) {layoutState.mScrollingOffset += layoutState.mAvailable;}recycleByLayoutState(recycler, layoutState);}if (stopOnFocusable && layoutChunkResult.mFocusable) {break;}}if (DEBUG) {validateChildOrder();}return start - layoutState.mAvailable;}

回收View 代码块解读

    private void recycleViewsFromStart(RecyclerView.Recycler recycler, int scrollingOffset,int noRecycleSpace) {if (scrollingOffset < 0) {if (DEBUG) {Log.d(TAG, "Called recycle from start with a negative value. This might happen"+ " during layout changes but may be sign of a bug");}return;}// ignore padding, ViewGroup may not clip children.final int limit = scrollingOffset - noRecycleSpace;final int childCount = getChildCount();if (mShouldReverseLayout) {for (int i = childCount - 1; i >= 0; i--) {View child = getChildAt(i);if (mOrientationHelper.getDecoratedEnd(child) > limit|| mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {// stop hererecycleChildren(recycler, childCount - 1, i);return;}}} else {for (int i = 0; i < childCount; i++) {View child = getChildAt(i);//limit 表示滑动多少 就会创建新View//如果说你的底部小于limit 说明你肯定要被回收//直到找到一个View的底部>limit 的地方if (mOrientationHelper.getDecoratedEnd(child) > limit|| mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {// stop hererecycleChildren(recycler, 0, i);return;}}}}

RecycleView 源码解析相关推荐

  1. Handler源码解析2

    Handler源码解析1 https://blog.csdn.net/qq_44076155/article/details/110676740 Handler源码解析2 https://blog.c ...

  2. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

  3. 谷歌BERT预训练源码解析(三):训练过程

    目录 前言 源码解析 主函数 自定义模型 遮蔽词预测 下一句预测 规范化数据集 前言 本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BE ...

  4. 谷歌BERT预训练源码解析(一):训练数据生成

    目录 预训练源码结构简介 输入输出 源码解析 参数 主函数 创建训练实例 下一句预测&实例生成 随机遮蔽 输出 结果一览 预训练源码结构简介 关于BERT,简单来说,它是一个基于Transfo ...

  5. Gin源码解析和例子——中间件(middleware)

    在<Gin源码解析和例子--路由>一文中,我们已经初识中间件.本文将继续探讨这个技术.(转载请指明出于breaksoftware的csdn博客) Gin的中间件,本质是一个匿名回调函数.这 ...

  6. Colly源码解析——结合例子分析底层实现

    通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...

  7. libev源码解析——定时器监视器和组织形式

    我们先看下定时器监视器的数据结构.(转载请指明出于breaksoftware的csdn博客) /* invoked after a specific time, repeatable (based o ...

  8. libev源码解析——定时器原理

    本文将回答<libev源码解析--I/O模型>中抛出的两个问题.(转载请指明出于breaksoftware的csdn博客) 对于问题1:为什么backend_poll函数需要指定超时?我们 ...

  9. libev源码解析——I/O模型

    在<libev源码解析--总览>一文中,我们介绍过,libev是一个基于事件的循环库.本文将介绍其和事件及循环之间的关系.(转载请指明出于breaksoftware的csdn博客) 目前i ...

最新文章

  1. 站覆盖范围_你了解无线覆盖范围和穿墙能力吗?别再走进这些误区了
  2. 怎样知道邮箱的端口_网络端口介绍
  3. MAC下homebre安装mysql
  4. 初学__Python——Python 自定义函数
  5. 前端Javascript与Nodejs的异同
  6. arcgis api for js入门开发系列十八风向流动图
  7. python中的class类使用方法[探索3]
  8. 二分法查找c语言程序_用C++写二分查找了!【手绘漫画】图解LeetCode之搜索插入位置(LeetCode 35)...
  9. 另菜单或工具栏按钮失效的mfc处理方法
  10. android中svn合并分支,Android Studio之SVN打分支、切换分支及合并分支
  11. python随机生成电话号码
  12. 知道如何防止域名被封,干货!赶紧收藏
  13. 你鼓舞了我是世界杯主题曲吗_20位鼓舞人心的科技女性
  14. Xposed原理分析
  15. Ceph Calamari软件包介绍
  16. 什么是“ Windows任务的主机进程”,为什么我的PC上运行着这么多主机?
  17. Sloan中性群落模型(NCM)推断群落构建原理及其R实现
  18. ICCV2021 | Vision Transformer中相对位置编码的反思与改进
  19. 云呐|机房监控服务平台,机房监控服务平台有哪些
  20. DVB误码率手持式场强仪科普说明

热门文章

  1. python什么是高阶函数_说说 Python 中的高阶函数
  2. Kanzi常用操作2
  3. 怎么设置表格根据窗口自动调整_Word排版技巧之表格美化,你值得拥有!
  4. 【vue插件篇】vue-form-check 表单验证
  5. Micropython实例之TPYBoardv102开发板DIY照相机
  6. java SSM多操作注解回滚
  7. Cesium 创建Geometry
  8. 调试小技巧---利用调用堆栈
  9. 数据测试常用的 Data Profiling 方法
  10. 【转】Android菜单详解——理解android中的Menu--不错