【安卓开发】RecycleView总结


前言

一、RecyclerView

参考文章

曾经列表数据的显示通常会使用到ListView,但RecyclerView的强大性能和泛用性早早打败了ListView成为现在的主流,让我们首先了解RecyclerView的基本使用方法。

1.viewholder状态

方法FLAG含义具体场景
isInvalid()FLAG_INVALIDviewholder数据无效1. 调用了setAdapter() 2. 调用了notifyDataSetChanged()等方法
isRemoved()FLAG_REMOVEDviewholder的数据已经被移除调用了notifyItemRemoved
isUpdated()FLAG_UPDATEviewholder的数据需要重新绑定1. 调用了onBindViewHolder 2. 调用了notifyItemChanged()
isBound()FLAG_BOUND数据已经绑定在某个item上,数据是有效状态调用了onBindViewHolder()

2.缓存机制

RecyclerVeiw的高性能的根源就在于它优秀的缓存机制。

参考文章

  1. 一级缓存
    第一层缓存是轻量的,每次都只会保存当前页面所显示的item,并且每次用完后就会清空缓存。RecycleView局部刷新用到的就是一级缓存实现复用。mChangedScrap主要是为列表项数据发生变化时的动画效果服务的,而mAttachedScrap应对的则是剩下的绝大部分场景。

  2. 二级缓存
    二级缓存CachView是用于当变得位置发生改变时,保存被移出屏幕的view,默认的容量是2,如果有需要可以修改这个容量数值(setItemViewCacheSize(int))。

  3. 三级缓存
    三级缓存也可以称为一个缓存池RecycledViewPool,会保存一二级缓存里存储不下的viewholder,类似一个回收站。它会根据viewType分类,将相同类型的ViewHolder存放在同一个ArrayList中。从一二级缓存取数值需要根据position,而三级缓存根据viewType

RecyclerView缓存复用机制的核心内容


3.布局管理器

参考文章

LinearLayoutManager: 线性布局管理器

三种构造方法:

  • LinearLayoutManager(Context context) :
    调用了第二个构造方法。

  • LinearLayoutManager(Context context,int orientation,boolean reverseLayout) :
    int orientation :方向,垂直(RecyclerView.VERTICAL)和水平(RecyclerView.HORIZONTA ),默认为垂直。(也可通过setOrientation()设置)
    boolean reverseLayout :是否倒序,设置为True,从最后一个item开始,倒序加载。此时,RecyclerView第一个item是添加进Adapter中的最后一个,最后一个item是第一个加进Adapter的数据,RecyclerView会自动滑到末尾,另外item整体是依靠下方的。(也可通过setReverseLayout()设置)

  • LinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,int defStyleRes) :
    可以使用自定义属性。


常用方法:

  • setOrientation():设置方向
  • setReverseLayout():设置是否倒序
  • setStackFromEnd():是否从底部开始展示
    setReverseLayout()与setStackFromEnd()共同点是都自动滑动尾部。不同点是setStackFromEnd(true)不会影响内部的数据顺序,怎么添加进Adapter的,就怎么展示。
  • scrollToPosition(int position):滑动到指定item
  • findFirstVisibleItemPosition():第一个可见的item的postion
    findLastVisibleItemPosition():最后一个可见的item的postion
    若RecyclerView不在屏幕中,则全部返回-1

GridLayoutManager: 表格布局管理器

构造函数:
其它参数含义与LinearLayoutManager相同,除了下方参数:

  • spanCount : 垂直方向时表示列数,水平方向时表示行数

setStackFromEnd()不支持GridLayoutManager(),但支持setReverseLayout(boolean)方法。


StaggeredGridLayoutManager: 瀑布流布局管理器

构造方法:

  • StaggeredGridLayoutManager(int spanCount, int orientation):
  • StaggeredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
StaggeredGridLayoutManager与GridLayoutManager区别
  • StaggeredGridLayoutManager效果图]:
    StaggeredGridLayoutManager效果图
  • GridLayoutManager效果图]:
    GridLayoutManager效果图
    两者之间的效果差异如上图:StaggeredGridLayoutManager的item是可以有不同的宽高的,而GridLayoutManager的item每行都是相同宽高的。

GridLayoutManager高度是由每行最高的决定,宽度则默认都是1,也就是平分宽度,但也可以通过设置spansize来修改。

     	val m = GridLayoutManager(context, 2)
     	m.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                            override fun getSpanSize(position: Int): Int {
                                when (position) {
                                    0 or 1 -> {
                                        return 3
                                    }

                                    else -> return 1;
                                }
                            }
                        }

而StaggeredGridLayoutManager中,下一行的元素位置是按照上一行item的bottom哪个最小就先放在哪个下边的。
需要注意的是,StaggeredGridLayoutManager中只有item的高度是wrap_content的时候,才应该设置ItemDecoration。

2.局部刷新的实现

当你只需要修改RecycleView的一部分的时候,每次都整个刷新会导致观感很差,实际上RecycleView早已实现了局部刷新,并且具有动画效果,再配合SmartRefreshLayout即可实现优雅的刷新!

RecycleView提供的局部更新函数如下:

增加
  1. notifyItemInserted(int position):更新在position之前插入的item
  2. notifyItemRangeInserted(int position, int count):更新在position之前插入的items,数目为count
删除
  1. notifyItemRemoved(int position):删除指定位置item
  2. notifyItemRangeRemoved(int positionStart, int itemCount):删除指定位置往后数itemCount个的items
修改
  1. notifyItemChanged(int position):修改指定位置item
  2. notifyItemChanged(int position, Object payload):详细参考文章:RecyclerView局部刷新机制
    灵活使用payload可以实现处理不同的局部刷新
    override fun onBindViewHolder(holder: BookTypeHolder, position: Int, payloads: MutableList<Any>) {
        if (payloads.isNotEmpty() && "0" == payloads[0]) {
            holder.view.isSelected = position == curPosition
        } else {
            // 如果没有 payloads ,或者不是我们指定的,还是返回默认的整个刷新
            onBindViewHolder(holder, position)
        }
    }

	//需要局部刷新时像这样调用即可:
        notifyItemChanged(prePosition, SELECT_CHANGED)

二、与SmartRefreshLayout、MutableList搭配

1.MutableList使用

kotlin中数组是Array<>,列表是list,list是不可改变的,当需要实现可改变的列表的话则需要使用MutableList。

  1. 创建:mutableListOf()
  2. 末尾/指定位置添加元素:add(item)/add(int, item)
  3. 添加另一个Lsit/Array/Set:addAll()
  4. 移除指定位置元素:removeAt(int)
  5. 移除指定元素:remove(item)
  6. 替换指定位置元素:set(int, item)/[int] =
  7. 取子列表:subList(start, end)
  8. 清空:clear()/removeAll(item)

2.SmartRefresh的使用

xml:

    <com.scwang.smart.refresh.layout.SmartRefreshLayout
        android:id="@+id/refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"
        app:srlEnableLoadMore="true">

        <com.scwang.smart.refresh.header.ClassicsHeader
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:srlEnableLastTime="false"
            app:srlPrimaryColor="@color/white"
            app:srlTextFinish="" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/read_view_rv"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <com.scwang.smart.refresh.footer.ClassicsFooter
            android:id="@+id/footer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:srlTextFinish="" />

    </com.scwang.smart.refresh.layout.SmartRefreshLayout>

SmartRefreshLayout使用:

		//下拉
		refresh_layout.setOnRefreshListener(refreshLayout -> {
            //加载之前的数据
            topRefresh();
            refreshLayout.finishRefresh(500);
        });
		//上拉
        refresh_layout.setOnLoadMoreListener(refreshLayout -> {
            //加载之后的数据
            bottomRefresh();
            refreshLayout.finishLoadMore(500);
        });

adapter中局部刷新函数:

    //刷新上方的数据
    fun notifyTop(items: List<A>) {
        var index = 0
        hpIndexs.forEach {
            list.add(index++, it)
        }
        this.notifyItemRangeInserted(0, list.size)
    }

    //刷新下方的数据
    fun notifyBottom(hpIndexs: List<HPIndex>) {
        val startIndex = list.size - 1
        hpIndexs.forEach {
            list.add(it)
        }
        this.notifyItemRangeInserted(startIndex, hpIndexs.size)
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值