1. RecycleView 如何设置分割线的?
它是读取系统自带的属性
R.attr.listDivider
属性,来设置分割线的,支持横向和纵向。
2. RecycleView 分割线的样式如何修改?
第一种办法:因为
R.attr.listDivider
定义在系统样式中,那么我们可以重写这个属性修改,如下:在
styles.xml
中添加该属性:1
2
3
4
5<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
....
<item name="android:listDivider">@drawable/drawable_bg</item>
</style>其中
drawable_bg
为自定义分割线的drawable
.第二种办法:可以通过自带的
setDrawable()
改变,如下:1
2
3
4DividerItemDecoration itemDecoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
Drawable drawable = getResources().getDrawable(R.drawable.drawable_bg);
itemDecoration.setDrawable(drawable);
recyclerView.addItemDecoration(itemDecoration);3. RecycleView 缓存
缓存涉及三个类,分别是:
Recycler
RecycledViewPool
ViewCachedExtension
Recycler
: 用于管理已经废弃或者与RecyclerView
分离的ViewHolder
mChangedScrap
: 与RecyclerView
分离的ViewHolder
列表mAttachedScrap
: 未与RecyclerView
分离的ViewHolder
列表mCachedViews
:ViewHolder
缓存列表
RecycledViewPool
:ViewHolder
缓存池ViewCachedExtension
: 开发者可以控制的ViewHolder
缓存的帮助类
获取缓存里的 ViewHolder
的关键方法是: tryGetViewHolderForPositionByDeadline
如下:
1 |
|
总结缓存的机制如下:
- 1.从
mChangedScrap
或mAttachScrap
中获取 - 2.从
mCacheViews
- 3.从
mRecycledViewPool
缓存池中获取
4. RecycleView 刷新闪屏
一般刷新:
1 | adapter.notifyItemChanged(0); 参数:position |
实际上会全部刷新,局部刷新应使用:
1 | adapter.notifyItemChanged(0,"q"); 参数: position,payload |
并且在 adapter
中重写方法: `onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads)
方法`
payloads
的 size
始终为1.
1 |
|
5. RecycleView 和 listView
//https://zhuanlan.zhihu.com/p/23339185
缓存层级不同
recycleView 比 listView 多两级缓存,支持开发者自定义缓存处理,支持多个recycleView共用同一个 recycleViewPool(缓存池)
listView
缓存(两级缓存):
是否需要回调createView | 是否需要回调bindVIew | 生命周期 | 备注 | |
---|---|---|---|---|
mActiveViews | 否 | 否 | onLayout函数周期内 | 用于屏幕内itemView快速重用 |
mScrapViews | 否 | 是 | 与mAdapter一致,当Adapter被更换时,mScrapViews即被清空 |
RecycrleView
缓存( 四级缓存):
是否回调createView | 回调bindVIew | 生命周期 | 备注 | |
---|---|---|---|---|
mAttachedScrap | 否 | 否 | onLayout | 用于屏幕内itemView快速重用 |
mCacheViews | 否 | 否 | 与mAdapter一致,当Adapter被更换时,mCacheVIews被缓存到mRecyclerPool | 默认缓存大小是2 |
mViewCacheExtension | 用户自定义实现 | |||
mRecyclerPool | 否 | 是 | 与自身生命周期一致,不再引用时被释放 | 默认大小是5 |
ListView
和 RecyclerView
缓存机制:
mActiveViews
和mAttachedScrap
功能相似,意义在于快速重用屏幕上可见的列表项itemView
,而不需要重新createView
和bindView
mScrapView
和mCachedViews
+mRecyclerViewPool
功能相似,意义在于缓存离开屏幕的itemView
,目的是让即将进入屏幕的itemView
重用RecycleView
的优势在于mCacheVIews
的使用,可以做到屏幕外的列表项itemView
进入屏幕内时也无须bindView
快速重用;mRecycleViewPool
可以供多个recycleView
共同使用,在特定场景下,如viewpager
加多个列表页有优势。
6. RecycleView 的回收复用机制的内部实现都是哪个类完成的?
RecycleView 的回收复用机制都是由内部类
Recycler
类,核心方法:tryGetViewHolderForPositionByDeadline()
方法中完成的。
随笔源码记录:
复用机制
1 | public View getViewForPosition(int position) { |
回收机制
也是 Recycler 类中的,核心方法:
recycleViewHolderInternal(holder)
1 | public void recycleView(View view) { |
回收的逻辑:由 LayoutManager
来遍历移出屏幕的卡位,然后对每个卡位进行回收操作,回收时,都是把 viewHolder
放在 mCachedViews
里面,如果mCachedViews
满了,那就在mCachedViews
里拿一个ViewHolder
扔到 ViewPool
缓存里,然后mCachedViews
就可以空出位置来放新回收的ViewHolder
了。
mCachedViews
里存放的ViewHolder
只有原本位置的卡位才能复用参考链接:https://blog.csdn.net/xJ032w2j4cCjhOW8s8/article/details/79946425
===================================================================================
updateViewCacheSize()
1 | void updateViewCacheSize() { |
在第一次向上滑动
7. RecycleView 性能优化
7.1 数据处理和视图加载适度分离
什么意思呢?就是我们异步从服务端拉取数据,拿到数据之后就把数据丢给
ViewHolder
进行处理,当然有些数据需要单独处理,那么其实这些处理逻辑也应该异步执行,这样的话就可以让adapter
在 notifyDatasetChanged 之后,ViewHolder 就可以简单处理视图与数据的绑定工作。
7.2 数据刷新
如果是个别数据发生改变,调用局部刷新的方法
7.3 布局优化
减少 GPU 过度绘制;
7.4 杂七杂八
- 升级 RecycleView 版本到 25.1.0 以上使用 Prefetch 功能,开启这个功能之后对页面复杂度的敏感性降低,在高复杂度情况下,Prefetch 可以显著提高页面流畅度。Android 5.0 以后引入
Render Thread
提升动画流畅性。- 如果item 高度固定的话,可以使用
RecyclerView.setHasFixSize(true)
来避免requestLayout
浪费资源;- 共用 RecycleViewPool ;
- 通过 getExtraLayoutSpace 来增加 RecyclerView 预留的额外空间,默认是一页数据的数量
8. 自定义属性获取完属性后为什么调用TypeArray.recycle()?
1 | /** |
1 | public class Resources{ |
看上面的那个大概意思就是从一个同步池子里获取到的,默认大小是5. 平常我们获取的属性是通过:
1 | TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.xx); |
context
的一个静态方法,点进去看看:
1 | //最终到了这里 |
SynchronizedPool
1 | /** |
维护一个同步栈结构的对象池,避免重复频繁创建属性值 TypeArray 对象,使用时记得调用 Recycle() 方法将不用的对象返回至对象池来达到重用的目的,如果不调用 recycle() 方法将会随着 Activity的每一次创建而创建,因此系统频繁创建 array, 对内存和性能是一个不小的开销,如果不使用池,每次都让 GC 来回收,很可能就会造成 OOM.
9. 自定义属性
1 | //自定义属性一般我们会在values-attr.xml 中定义,如下: |
两种方式有什么区别呢?
第一种方式会把有关这个控件的属性包裹起来,达到一个分组的概念,不零散,属性的使用范围更加明确,
第一种方式获取属性值:
1 | TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.customerView); |
第二种方式获取属性值:
1 | int[] array = {R.attr.AloneAttr}; |