港北网站建设,网站优化可以做哪些优化,网站建设 橙,成都优化官网推广listview缓存请看: listview优化和详解RecycleView 和 ListView对比#xff1a;使用方法上ListView#xff1a;继承重写 BaseAdapter#xff0c;自定义 ViewHolder 与 converView优化。RecyclerView: 继承重写 RecyclerView.Adapter 与 RecyclerView.ViewHolder。设置 Layou…listview缓存请看: listview优化和详解RecycleView 和 ListView对比使用方法上ListView继承重写 BaseAdapter自定义 ViewHolder 与 converView优化。RecyclerView: 继承重写 RecyclerView.Adapter 与 RecyclerView.ViewHolder。设置 LayoutManager 来展示不同的布局样式区别ViewHolder的编写规范化ListView是需要自己定义的而RecyclerView是规范好的
RecyclerView复用item全部搞定不需要像ListView那样setTag()与getTag()
RecyclerView多了一些LayoutManager工作但实现了布局效果多样化 2. 动画api在RecyclerView中自带动画效果例如notifyItemChanged(), notifyDataInserted(), notifyItemMoved()等等同时内置有许多动画API如果需要自定义动画效果可以通过实现RecyclerView.ItemAnimator类完成自定义动画效果然后调用RecyclerView.setItemAnimator()但是ListView并没有实现动画效果需要在Adapter自己自定义3. 缓存区别ListView和RecyclerView最大的区别在于数据源改变时的缓存的处理逻辑ListView是二级缓存而RecyclerView则是更加灵活地采用了四级缓存。recycleview有四级缓存mAttachedScrap(屏幕内)用于屏幕内itemview快速重用不需要重新createView和bindViewmCacheViews(屏幕外)保存最近移出屏幕的ViewHolder包含数据和position信息复用时必须是相同位置的ViewHolder才能复用应用场景在那些需要来回滑动的列表中当往回滑动时能直接复用ViewHolder数据不需要重新bindView。mViewCacheExtension(自定义缓存)不直接使用需要用户自定义实现默认不实现。mRecyclerPool(缓存池)当cacheView满了后或者adapter被更换将cacheView中移出的ViewHolder放到Pool中放之前会把ViewHolder数据清除掉所以复用时需要重新bindView。四级缓存完整存取缓存流程是保存缓存流程插入或是删除itemView时先把屏幕内的ViewHolder保存至AttachedScrap中滑动屏幕的时候先消失的itemview会保存到CacheViewCacheView大小默认是2超过数量的话按照先入先出原则移出头部的itemview保存到RecyclerPool缓存池如果有自定义缓存就会保存到自定义缓存里RecyclerPool缓存池会按照itemview的itemtype(viewHolder类型)进行保存每个viewHolder类型缓存个数为5个超过就会被回收。获取缓存流程(getViewFromPos()方法)AttachedScrap中获取通过pos匹配holder——获取失败从CacheView中获取也是通过pos获取holder缓存——获取失败从自定义缓存中获取缓存——获取失败从mRecyclerPool中获取——获取失败重新创建viewholder——createViewHolder并bindview。(如果某级缓存获取成功后会对该级缓存进行删除以免占用缓存) 了解了缓存结构和缓存流程我们再来看看具体的问题 滑动10个item再滑回去会有几个执行onBindView参考文:https://www.cnblogs.com/jimuzz/p/14040674.html由之前的缓存结构可知需要重新执行onBindView的只有一种缓存区就是缓存池mRecyclerPool。所以我们假设从加载RecyclView开始盘的话页面假设可以容纳7条数据首先7条数据会依次调用onCreateViewHolder和onBindViewHolder。往下滑一条position7那么会把position0的数据放到mCacheViews中。此时mCacheViews缓存区数量为1mRecyclerPool数量为0。然后新出现的position7的数据通过postion在mCacheViews中找不到对应的ViewHolder通过itemtype也在mRecyclerPool中找不到对应的数据所以会调用onCreateViewHolder和onBindViewHolder方法。再往下滑一条数据position8如上。再往下滑一条数据position9position2的数据会放到mCacheViews中但是由于mCacheViews缓存区默认容量为2所以position0的数据会被清空数据然后放到mRecyclerPool缓存池中。而新出现的position9数据由于在mRecyclerPool中还是找不到相应type的ViewHolder所以还是会走onCreateViewHolder和onBindViewHolder方法。所以此时mCacheViews缓存区数量为2mRecyclerPool数量为1。再往下滑一条数据position10这时候由于可以在mRecyclerPool中找到相同viewtype的ViewHolder了。所以就直接复用了并调用onBindViewHolder方法绑定数据。后面依次类推刚消失的两条数据会被放到mCacheViews中再出现的时候是不会调用onBindViewHolder方法而复用的第三条数据是从mRecyclerPool中取得就会调用onBindViewHolder方法了。4所以这个问题就得出结论了假设mCacheViews容量为默认值2如果一开始滑动的是新数据那么滑动10个就会走10个bindview方法。然后滑回去会走10-2个bindview方法。一共18次调用。如果一开始滑动的是老数据那么滑动10-2个就会走8个bindview方法。然后滑回去会走10-2个bindview方法。一共16次调用。但是但是实际情况又有点不一样。因为Recycleview在v25版本引入了一个新的机制预取机制。预取机制就是在滑动过程中会把将要展示的一个元素提前缓存到mCachedViews中所以滑动10个元素的时候第11个元素也会被创建也就多走了一次bindview方法。但是滑回去的时候不影响因为就算提前取了一个缓存数据只是把bindview方法提前了并不影响总的绑定item数量。所以滑动的是新数据的情况下就会多一次调用bindview方法。5总结问题怎么答呢四级缓存和流程说一下。滑动10个再滑回去bindview可以是19次调用可以是16次调用。缓存的其实就是缓存item的view在Recycleview中就是viewholder。cachedView就是mCacheViews缓存区中的view是不需要重新绑定数据的。其他问题:为啥需要Scrap一级缓存?主要用在插入或是删除itemView时先把屏幕内的ViewHolder保存至AttachedScrap中作用在LayoutManager中它仅仅把需要从ViewGroup中移除的子view设置它的父view为null从而实现了从RecyclerView中移除操作detachView()。不过如果是全部刷新适配器的notifyDataSetChanged方法那么不会走Scrap缓存;RecycleView 滑动冲突解决:除了可以参考之前我的文章里提到的两种常用解决方案: https://blog.csdn.net/emmmsuperdan/article/details/79645792如果是双层滑动嵌套情况可以优化成NestScrollView嵌套RecyclerView方案但是要注意设置RecyclerView.setNestedScrollingEnabled(false)这个方法用来取消RecyclerView本身的滑动效果。这是因为RecyclerView默认是setNestedScrollingEnabled(true)这个方法的含义是支持嵌套滚动的。也就是说当它嵌套在NestedScrollView中时,默认会随着NestedScrollView滚动而滚动,放弃了自己的滚动。 RecycleView绘制可参考文:https://blog.csdn.net/qq_32019367/article/details/114656817在开始onMeasure的地方对Rv的宽高Mode做了判断如果是固定宽和高(Exactly_Mode)或者设置了setHasFixedSize就直接return开始执行下一步layout为啥固定宽高不需要measure呢?因为固定宽高一页子view的数量就确定了直接做layout摆放就行因此如果在使用rv时知道是固定宽高可以提前指定或setHasFixedSize,这样更节省绘制性能 protected void onMeasure(int widthSpec, int heightSpec) {if (mLayout null) {defaultOnMeasure(widthSpec, heightSpec);return;}if (mLayout.isAutoMeasureEnabled()) {final int widthMode MeasureSpec.getMode(widthSpec);final int heightMode MeasureSpec.getMode(heightSpec);mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);final boolean measureSpecModeIsExactly widthMode MeasureSpec.EXACTLY heightMode MeasureSpec.EXACTLY;if (measureSpecModeIsExactly || mAdapter null) {return;}}else {if (mHasFixedSize) {mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);return;}...}
...
}