RecyclerView的使用

与ListView相比,同样具有item回收复用功能,RecyclerView把ViewHolder的实现封装了起来,使用时要实现自己的ViewHolder。

首先,跟ListView一样,要定义一个数据适配器,这里要继承RecyclerView的内部抽象类,RecyclerView.Adapter< VH extends ViewHolder>,泛型参数为ViewHolder。

数据适配器


public static abstract class Adapter<VH extends ViewHolder> {
       public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
       public abstract void onBindViewHolder(VH holder, int position);
       public abstract int getItemCount();
       ...
}

必须重写的方法有三个:

  • onCreateViewHolder:加载item视图,用整个item构造ViewHolder(不用实例化item里面的每个组件)并返回ViewHolder对象。item内每个组件的实例化在ViewHolder中完成
  • onBindViewHolder:在此方法内绑定视图与数据,传入参数为ViewHolder对象与item位置,实现在相应位置绑定数据。
  • getItemCount:与定义ListView的BaseAdapter类似,返回数据个数,同样的也可以重写,getViewType和getItemId

示例:

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.lv_item, parent, false);
    ViewHolder vh = new ViewHolder(v);
    return vh;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder h, final int position) {
    UserBean user = mDataSet.get(position);
    final ViewHolder holder = (ViewHolder) h;
    holder.nameTv.setText(user.getName());
    holder.phoneTv.setText(user.getPhone());
    holder.groupTv.setText(user.getGroup());
    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            listener.onItemClick(holder.itemView, position);
        }
    });
}
@Override
public int getItemCount() {
    return mDataSet.size();
}

ViewHolder


上面定义Adaper的时候,实例化了ViewHolder对象,与BaseAdapter类似,ViewHolder也要在Adapter内被定义为静态内部类。不同的是,RecyclerView内部已经封装好了ViewHolder,只要继承实现即可。

监听器


RecyclerView默认并没有事件监听器,需要自己定义实现。比如,item里面有Button,一般就在Adapter里面设置回调接口,以及注册回调的方法。使用时,只要实现该接口并注册即可,在Adapter内部,Button会实现自己一般的监听器,并在onClick方法中直接调用Adapter里面实现的接口的方法,这样就完成了事件监听。

LayoutManager


通过RecyclerView的setLayoutManager方法可以设置不同的布局方式。

…a standard vertically scrolling list, a uniform grid, staggered grids, horizontally scrolling collections and more.

由文档可以看到,有传统的垂直ListView,有表格布局,有交错表格布局(瀑布流),有水平滑动布局。查看类层次,也发现系统默认有三种布局。

其他可选项


分隔符与动画效果:

  • ItemDecoration , RecyclerView默认item之间没有分隔符,要自己实现

    mRecyclerView.addItemDecoration() 
  • ItemAnimator,RecyclerView删除和插入时的动画效果

    //默认的动画效果
    mRecyclerView.setItemAnimator(new DefaultItemAnimator());

注意:这里更新数据集不是用dapter.notifyDataSetChanged()而是 notifyItemInserted(position)与otifyItemRemoved(position) 否则没有动画效果。

相关阅读:鸿洋的RecyclerView讲解

图片乱序问题


这个在ListView中也是个问题,或者说凡是在异步加载的过程总都要注意。由于ListView和RecyclerView都有视图回收机制,所以当我们下载好图片后,很可能要显示的ImageView已经滚出屏幕,并且回收使用,从屏幕下方滚入(注意,此时程序的逻辑已经在该ImageView再次下载并显示图片了),此时,加载图片,但是很快新的图片有下载并加载,所以一个ImageView会出现先后显示两张图片的情况,就是图片错乱的问题。

解决方法

  • findViewWithTag:使用View的setTag方法存储url,绑定了view和url,通过url反向寻找view是否还在屏幕上并且没有被回收利用过,因为如果被利用过,view会存储了新的url。但是,此君有个缺点,异步任务会一直执行,直到下载好图片,此时才会判断要不要加载,这就无形中浪费了资源。
  • 双向绑定:ImageView和AsyncTask实例双向绑定,因为ImageView滑出屏幕,并且重新利用时会绑定另一个AsyncTask。每个异步任务AsyncTask执行下载图片完毕后,会检查自己持有的ImageView实例所绑定的AsyncTask实例是不是自己,如果不是自己那就不显示图片。另外,为了让已经无用的异步加载任务退出,每次在使用ImageView前会先清除潜在的异步任务。

默认图片

图片错乱还有一个小细节,因为我们会缓存ImageView,所以ImageView回收后,上面的图像数据还在,当再次利用时,ImageView上面的图片,很可能不是刚下载好的,而是上一次的图像缓存。

解决方法:

  • 通用方法:每次重新利用前,首先设置一个空图片,冲掉先前的旧图片。
  • RecyclerView:在RecyclerView.Adapter中有一个方法onViewRecycled,每次view被回收时就会回调,可以在这里把视图设为空。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值