当前位置: 首页 > news >正文

做网站建设推荐艺术字体转换器

做网站建设推荐,艺术字体转换器,三好街 网站建设,织梦网站怎么做seo概述 RecyclerView 是 Android 中用于高效显示大量数据的视图组件#xff0c;它是 ListView 的升级版本#xff0c;支持更灵活的布局和功能。 我们创建一个RecyclerView的Adapter#xff1a; public class MyRecyclerView extends RecyclerView.AdapterMyRecyclerVie…概述 RecyclerView 是 Android 中用于高效显示大量数据的视图组件它是 ListView 的升级版本支持更灵活的布局和功能。 我们创建一个RecyclerView的Adapter public class MyRecyclerView extends RecyclerView.AdapterMyRecyclerView.MyHolder {private ListString strings;private Context context;public MyRecyclerView(ListString strings, Context context) {this.strings strings;this.context context;}NonNullOverridepublic MyRecyclerView.MyHolder onCreateViewHolder(NonNull ViewGroup parent, int viewType) {View view LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);MyRecyclerView.MyHolder viewHolder new MyHolder(view);Log.d(MyRecyclerView, onCreateViewHolder: );return viewHolder;}Overridepublic void onBindViewHolder(NonNull MyRecyclerView.MyHolder holder, int position) {holder.textView.setText(第 position 项);Log.d(MyRecyclerView, onBindViewHolder: position);}Overridepublic int getItemCount() {return strings null ? 0 : strings.size();}public class MyHolder extends RecyclerView.ViewHolder {private TextView textView;public MyHolder(NonNull View itemView) {super(itemView);textView itemView.findViewById(android.R.id.text1);}} } 我们在onCreateViewHolder和onBindViewHolder都打印log。 onCreateViewHolder()会在创建一个新view的时候调用onBindViewHolder()会在已存在view绑定数据的时候调用。 我们来看一下运行时打印的log 在最开始加载view的时候两个方法onCreateViewHolder()和onBindViewHolder()都执行了但是当我们上下滑动RecyclerView的时候我们会发现只执行了onBindViewHolder()方法。所以说RecyclerView并不是会一直重新创建View而是会对view进行复用。 复用机制 当我们想去通过看源码去了解缓存复用机制的时候我们要去想看源码的入口在哪里。上文我们提到是在滑动RecyclerView的时候进行了缓存复用所以我们会想到去看 onTouchEvent 这个方法 Override public boolean onTouchEvent(MotionEvent e) {...case MotionEvent.ACTION_MOVE: {final int index e.findPointerIndex(mScrollPointerId);if (index 0) {Log.e(TAG, Error processing scroll; pointer index for id mScrollPointerId not found. Did any MotionEvents get skipped?);return false;}final int x (int) (e.getX(index) 0.5f);final int y (int) (e.getY(index) 0.5f);int dx mLastTouchX - x;int dy mLastTouchY - y;if (mScrollState ! SCROLL_STATE_DRAGGING) {boolean startScroll false;if (canScrollHorizontally) {if (dx 0) {dx Math.max(0, dx - mTouchSlop);} else {dx Math.min(0, dx mTouchSlop);}if (dx ! 0) {startScroll true;}}if (canScrollVertically) {if (dy 0) {dy Math.max(0, dy - mTouchSlop);} else {dy Math.min(0, dy mTouchSlop);}if (dy ! 0) {startScroll true;}}if (startScroll) {setScrollState(SCROLL_STATE_DRAGGING);}}if (mScrollState SCROLL_STATE_DRAGGING) {mReusableIntPair[0] 0;mReusableIntPair[1] 0;if (dispatchNestedPreScroll(canScrollHorizontally ? dx : 0,canScrollVertically ? dy : 0,mReusableIntPair, mScrollOffset, TYPE_TOUCH)) {dx - mReusableIntPair[0];dy - mReusableIntPair[1];// Updated the nested offsetsmNestedOffsets[0] mScrollOffset[0];mNestedOffsets[1] mScrollOffset[1];// Scroll has initiated, prevent parents from interceptinggetParent().requestDisallowInterceptTouchEvent(true);}mLastTouchX x - mScrollOffset[0];mLastTouchY y - mScrollOffset[1];if (scrollByInternal(canScrollHorizontally ? dx : 0,canScrollVertically ? dy : 0,e)) {getParent().requestDisallowInterceptTouchEvent(true);}if (mGapWorker ! null (dx ! 0 || dy ! 0)) {mGapWorker.postFromTraversal(this, dx, dy);}}} break;...return true; }在case:MotionEvent.ACTION_MOVE里有 scrollByInternal() 这个方法 boolean scrollByInternal(int x, int y, MotionEvent ev) {int unconsumedX 0;int unconsumedY 0;int consumedX 0;int consumedY 0;consumePendingUpdateOperations();if (mAdapter ! null) {mReusableIntPair[0] 0;mReusableIntPair[1] 0;scrollStep(x, y, mReusableIntPair);consumedX mReusableIntPair[0];consumedY mReusableIntPair[1];unconsumedX x - consumedX;unconsumedY y - consumedY;}if (!mItemDecorations.isEmpty()) {invalidate();}mReusableIntPair[0] 0;mReusableIntPair[1] 0;dispatchNestedScroll(consumedX, consumedY, unconsumedX, unconsumedY, mScrollOffset,TYPE_TOUCH, mReusableIntPair);unconsumedX - mReusableIntPair[0];unconsumedY - mReusableIntPair[1];boolean consumedNestedScroll mReusableIntPair[0] ! 0 || mReusableIntPair[1] ! 0;// Update the last touch co-ords, taking any scroll offset into accountmLastTouchX - mScrollOffset[0];mLastTouchY - mScrollOffset[1];mNestedOffsets[0] mScrollOffset[0];mNestedOffsets[1] mScrollOffset[1];if (getOverScrollMode() ! View.OVER_SCROLL_NEVER) {if (ev ! null !MotionEventCompat.isFromSource(ev, InputDevice.SOURCE_MOUSE)) {pullGlows(ev.getX(), unconsumedX, ev.getY(), unconsumedY);}considerReleasingGlowsOnScroll(x, y);}if (consumedX ! 0 || consumedY ! 0) {dispatchOnScrolled(consumedX, consumedY);}if (!awakenScrollBars()) {invalidate();}return consumedNestedScroll || consumedX ! 0 || consumedY ! 0; }里面的 scrollStep() 方法 void scrollStep(int dx, int dy, Nullable int[] consumed) {startInterceptRequestLayout();onEnterLayoutOrScroll();TraceCompat.beginSection(TRACE_SCROLL_TAG);fillRemainingScrollValues(mState);int consumedX 0;int consumedY 0;if (dx ! 0) {consumedX mLayout.scrollHorizontallyBy(dx, mRecycler, mState);}if (dy ! 0) {consumedY mLayout.scrollVerticallyBy(dy, mRecycler, mState);}TraceCompat.endSection();repositionShadowingViews();onExitLayoutOrScroll();stopInterceptRequestLayout(false);if (consumed ! null) {consumed[0] consumedX;consumed[1] consumedY;} }scrollHorizontallyBy 与 scrollVerticallyBy Override public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,RecyclerView.State state) {if (mOrientation VERTICAL) {return 0;}return scrollBy(dx, recycler, state); } Override public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,RecyclerView.State state) {if (mOrientation HORIZONTAL) {return 0;}return scrollBy(dy, recycler, state); }两个都执行的 scrollBy int scrollBy(int delta, RecyclerView.Recycler recycler, RecyclerView.State state) {if (getChildCount() 0 || delta 0) {return 0;}ensureLayoutState();mLayoutState.mRecycle true;final int layoutDirection delta 0 ? LinearLayoutManager.LayoutState.LAYOUT_END : LinearLayoutManager.LayoutState.LAYOUT_START;final int absDelta Math.abs(delta);updateLayoutState(layoutDirection, absDelta, true, state);final int consumed mLayoutState.mScrollingOffset fill(recycler, mLayoutState, state, false);if (consumed 0) {if (DEBUG) {Log.d(TAG, Dont have any more elements to scroll);}return 0;}final int scrolled absDelta consumed ? layoutDirection * consumed : delta;mOrientationHelper.offsetChildren(-scrolled);if (DEBUG) {Log.d(TAG, scroll req: delta scrolled: scrolled);}mLayoutState.mLastScrollDelta scrolled;return scrolled; }里面的 fill 方法最为关键 int fill(RecyclerView.Recycler recycler, LinearLayoutManager.LayoutState layoutState,RecyclerView.State state, boolean stopOnFocusable) {...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 ! LinearLayoutManager.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; }这个方法功能是填充给定的布局通过while循环不断进行填充其中的 layoutChunk() 方法 void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,LayoutState layoutState, LayoutChunkResult result) {View view layoutState.next(recycler);//获取下一项需要布局的视图if (view null) {if (DEBUG layoutState.mScrapList null) {throw new RuntimeException(received null view when unexpected);}// if we are laying out views in scrap, this may return null which means there is// no more items to layout.result.mFinished true;return;}RecyclerView.LayoutParams params (RecyclerView.LayoutParams) view.getLayoutParams();if (layoutState.mScrapList null) {if (mShouldReverseLayout (layoutState.mLayoutDirection LayoutState.LAYOUT_START)) {addView(view);//将视图添加到布局的末尾} else {addView(view, 0);//将视图添加到布局的开头}} else {if (mShouldReverseLayout (layoutState.mLayoutDirection LayoutState.LAYOUT_START)) {addDisappearingView(view);} else {addDisappearingView(view, 0);}}... }依次点击 最后我们就找到了回收复用的最关键的代码。 ViewHolder tryGetViewHolderForPositionByDeadline(int position,boolean dryRun, long deadlineNs) {if (position 0 || position mState.getItemCount()) {throw new IndexOutOfBoundsException(Invalid item position position ( position ). Item count: mState.getItemCount() exceptionLabel());}boolean fromScrapOrHiddenOrCache false;ViewHolder holder null;// 0) If there is a changed scrap, try to find from thereif (mState.isPreLayout()) {holder getChangedScrapViewForPosition(position);fromScrapOrHiddenOrCache holder ! null;}// 1) Find by position from scrap/hidden list/cacheif (holder null) {holder getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);if (holder ! null) {if (!validateViewHolderForOffsetPosition(holder)) {// recycle holder (and unscrap if relevant) since it cant be usedif (!dryRun) {// we would like to recycle this but need to make sure it is not used by// animation logic etc.holder.addFlags(ViewHolder.FLAG_INVALID);if (holder.isScrap()) {removeDetachedView(holder.itemView, false);holder.unScrap();} else if (holder.wasReturnedFromScrap()) {holder.clearReturnedFromScrapFlag();}recycleViewHolderInternal(holder);}holder null;} else {fromScrapOrHiddenOrCache true;}}}if (holder null) {final int offsetPosition mAdapterHelper.findPositionOffset(position);if (offsetPosition 0 || offsetPosition mAdapter.getItemCount()) {throw new IndexOutOfBoundsException(Inconsistency detected. Invalid item position position (offset: offsetPosition ). state: mState.getItemCount() exceptionLabel());}final int type mAdapter.getItemViewType(offsetPosition);// 2) Find from scrap/cache via stable ids, if existsif (mAdapter.hasStableIds()) {holder getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),type, dryRun);if (holder ! null) {// update positionholder.mPosition offsetPosition;fromScrapOrHiddenOrCache true;}}if (holder null mViewCacheExtension ! null) {// We are NOT sending the offsetPosition because LayoutManager does not// know it.final View view mViewCacheExtension.getViewForPositionAndType(this, position, type);if (view ! null) {holder getChildViewHolder(view);if (holder null) {throw new IllegalArgumentException(getViewForPositionAndType returned a view which does not have a ViewHolder exceptionLabel());} else if (holder.shouldIgnore()) {throw new IllegalArgumentException(getViewForPositionAndType returned a view that is ignored. You must call stopIgnoring before returning this view. exceptionLabel());}}}if (holder null) { // fallback to poolif (DEBUG) {Log.d(TAG, tryGetViewHolderForPositionByDeadline( position ) fetching from shared pool);}holder getRecycledViewPool().getRecycledView(type);if (holder ! null) {holder.resetInternal();if (FORCE_INVALIDATE_DISPLAY_LIST) {invalidateDisplayListInt(holder);}}}if (holder null) {long start getNanoTime();if (deadlineNs ! FOREVER_NS !mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {// abort - we have a deadline we cant meetreturn null;}holder mAdapter.createViewHolder(RecyclerView.this, type);if (ALLOW_THREAD_GAP_WORK) {// only bother finding nested RV if prefetchingRecyclerView innerView findNestedRecyclerView(holder.itemView);if (innerView ! null) {holder.mNestedRecyclerView new WeakReference(innerView);}}long end getNanoTime();mRecyclerPool.factorInCreateTime(type, end - start);if (DEBUG) {Log.d(TAG, tryGetViewHolderForPositionByDeadline created new ViewHolder);}}}// This is very ugly but the only place we can grab this information// before the View is rebound and returned to the LayoutManager for post layout ops.// We dont need this in pre-layout since the VH is not updated by the LM.if (fromScrapOrHiddenOrCache !mState.isPreLayout() holder.hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST)) {holder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);if (mState.mRunSimpleAnimations) {int changeFlags ItemAnimator.buildAdapterChangeFlagsForAnimations(holder);changeFlags | ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT;final ItemHolderInfo info mItemAnimator.recordPreLayoutInformation(mState,holder, changeFlags, holder.getUnmodifiedPayloads());recordAnimationInfoIfBouncedHiddenView(holder, info);}}boolean bound false;if (mState.isPreLayout() holder.isBound()) {// do not update unless we absolutely have to.holder.mPreLayoutPosition position;} else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {if (DEBUG holder.isRemoved()) {throw new IllegalStateException(Removed holder should be bound and it should come here only in pre-layout. Holder: holder exceptionLabel());}final int offsetPosition mAdapterHelper.findPositionOffset(position);bound tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);}final ViewGroup.LayoutParams lp holder.itemView.getLayoutParams();final LayoutParams rvLayoutParams;if (lp null) {rvLayoutParams (LayoutParams) generateDefaultLayoutParams();holder.itemView.setLayoutParams(rvLayoutParams);} else if (!checkLayoutParams(lp)) {rvLayoutParams (LayoutParams) generateLayoutParams(lp);holder.itemView.setLayoutParams(rvLayoutParams);} else {rvLayoutParams (LayoutParams) lp;}rvLayoutParams.mViewHolder holder;rvLayoutParams.mPendingInvalidate fromScrapOrHiddenOrCache bound;return holder; }从代码中我们可以看出复用的并不是一个个控件而是 ViewHolder(ItemView) 。 我们可以通过上面代码看出来RecyclerView的复用机制 第一层Changed Scrap 代码 if (mState.isPreLayout()) {holder getChangedScrapViewForPosition(position);fromScrapOrHiddenOrCache holder ! null; }解释 如果当前处于预布局isPreLayout true会优先从变更缓存中获取。getChangedScrapViewForPosition(position)查找变更缓存mChangedScrap这里保存的是那些被标记为需要更新的ViewHolder。如果找到直接返回不需要从其他层中查找。 在 RecyclerView 的布局过程中预布局Pre-Layout 是 RecyclerView 为支持动画效果如插入、删除、移动等操作而执行的一个特殊布局阶段。 以下操作都会触发 预布局阶段并可能从变更缓存中获取视图来进行后续处理 插入、移除、范围更新notifyItemInserted, notifyItemRemoved, notifyItemRangeChanged 等视图的布局和数据绑定例如setAdapter, setHasStableIds布局管理器或动画的变化setLayoutManager, setItemAnimator视图的移动notifyItemMoved所有与动画相关的操作包括添加、删除、移动动画 第二层Scrap/Hidden/Cache 代码 if (holder null) {holder getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);if (holder ! null) {if (!validateViewHolderForOffsetPosition(holder)) {if (!dryRun) {holder.addFlags(ViewHolder.FLAG_INVALID);if (holder.isScrap()) {removeDetachedView(holder.itemView, false);holder.unScrap();} else if (holder.wasReturnedFromScrap()) {holder.clearReturnedFromScrapFlag();}recycleViewHolderInternal(holder);}holder null;} else {fromScrapOrHiddenOrCache true;}} }解释 如果第一层缓存未命中尝试从 普通缓存层中获取包括 Scrap表示那些视图项暂时不可见但还可以复用的视图它们是最常见的一种缓存方式。被标记为废弃的视图在没有被回收之前可以复用。Hidden隐藏视图与 Scrap 类似但它们的存在通常是为了支持更复杂的布局切换、动画等。它们在显示区域外但仍然保留在缓存中直到需要重新显示。CacheRecyclerView 使用缓存来存储那些根据视图 ID 或类型等条件频繁访问的视图。它们通常在视图池中存储较长时间直到达到缓存容量限制。 调用 validateViewHolderForOffsetPosition(holder)检查缓存的有效性 如果无效比如位置错位将其回收。如果有效标记fromScrapOrHiddenOrCache true。 第三层Stable ID Cache 代码 if (holder null mAdapter.hasStableIds()) {holder getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);if (holder ! null) {holder.mPosition offsetPosition;fromScrapOrHiddenOrCache true;} }解释 如果Adapter支持稳定IDhasStableIds true尝试通过稳定ID查找缓存中的ViewHolder。调用getScrapOrCachedViewForId通过ID获取匹配的ViewHolder。如果找到将其位置更新为offsetPosition并标记为来自缓存。 如何启用 Stable ID 为了使 RecyclerView 使用 Stable ID Cache必须确保以下两点 实现 hasStableIds() 方法 你需要在你的 RecyclerView.Adapter 中重写 hasStableIds() 方法并返回 true。这是启用 Stable ID Cache 的前提。返回稳定的 ID 在适配器的 getItemId() 方法中为每个项返回唯一的 ID。这个 ID 通常是数据中的唯一标识符比如数据库中的主键。 示例代码 public class MyAdapter extends RecyclerView.AdapterMyViewHolder {Overridepublic boolean hasStableIds() {return true; // 启用 Stable ID}Overridepublic long getItemId(int position) {// 假设你的数据项有一个唯一的 id 字段return myDataList.get(position).getId();}// 其他适配器方法... }或者在构造方法中进行设置 public MyRecyclerViewAdapter(ListString strings, Context context) {this.strings strings;this.context context;setHasStableIds(true); // 启用稳定 ID }第四层Recycled Pool 代码 if (holder null) {holder getRecycledViewPool().getRecycledView(type);if (holder ! null) {holder.resetInternal();} }解释 Recycled Pool 是 RecyclerView 内部维护的一个缓存池用于存储已经被回收并不再使用的视图View。这些视图通常是已经滑出屏幕或者暂时不可见的视图。通过回收池RecyclerView 可以避免每次滚动时都重新创建视图而是将已回收的视图重新利用从而提升滚动性能。 回收池的工作机制是RecyclerView 会在视图不再需要时将它们放入回收池即已回收的视图池。当需要新的视图时RecyclerView 会从回收池中获取一个合适的视图进行重用。 回收池存储的是所有超出缓存数量限制的ViewHolder按type分类。 如果找到调用resetInternal()重置其状态。 最后一层创建新 ViewHolder 代码中涉及的部分 if (holder null) {holder mAdapter.createViewHolder(RecyclerView.this, type); }说明 如果所有缓存机制都未找到匹配的 ViewHolder最终会调用 Adapter.createViewHolder 来创建新的实例。这是性能代价最高的一步。 我们通过点击 就可以找到我们每次写Adapter都用重写的 onCreateViewHolder方法了。 在后面的代码中我们依次点击 就可以找到我们每次写Adapter都用重写的 onBindViewHolder方法了。 已经到底啦
http://www.w-s-a.com/news/625252/

相关文章:

  • 大连网站优化技术长沙高端网站建设服务
  • 郎创网站建设做的网站 v2ex
  • 广东网站建设教程江西城乡住房建设网站
  • 做ppt卖给网站wordpress insert
  • 文化传媒公司网站模板wordpress转typecho
  • 网站建设设计视频郑州 服装网站建设
  • 网站建设什么公司好织梦cms默认密码
  • 大型网站 空间网上商城官网入口
  • 成都全美网站建设江苏专业网站建设
  • 足球网站模板有帮忙做阿里巴巴网站的吗
  • 建设厅报名网站京东网站的建设与发展前景
  • 金寨县住房和城乡建设部网站网页作业怎么做一个网站
  • 做ppt模板网站有哪些内容wap是什么意思卡老师
  • 网站建设一定要域名吗网站后台关键词设置
  • 标书制作公司网站坪山网站建设哪家便宜
  • 防止做网站的人修改数值门户网站架构
  • 电子项目外包网站考二建需要什么学历和专业
  • 做网站推广引流效果好吗电商推广技巧
  • 亦庄网站建设价格广州网站推广服务
  • 十大免费ppt网站下载重庆在线高校平台登录
  • 做环保网站案例百度seo教程
  • 体育用品网站模板网站建设话术
  • 潍坊网站建设服务商做网站多久能盈利
  • 嘉定区做网站房产信息查询官网
  • 网站直播间 是怎么做的唐山论坛建站模板
  • 深圳洲聚网站建设wordpress 泛解析
  • 五金东莞网站建设技术支持wordpress 添加模板
  • 网站申请专利春节网页设计素材
  • 进网站备案md风格的wordpress主题
  • 如何建站网站十大免费建站app