RecyclerView使用踩坑全过程

来源:互联网 发布:手碟软件 编辑:程序博客网 时间:2024/05/29 15:37

Long long ago,谷歌就推出了RecyclerView来替代ListView,有人说它好,功能强大,方便扩展,也有人说它极其难用,最近Coder哥的项目需要代码重构,于是就想用RecyclerView来替代ListView,在此总结一下使用过程中的一些坑点,为大家今后的使用铺平道路。

一、点击事件及分割线需自定义

这一点不需要我多说,大家自行谷歌,代码很全,不在此造轮子了。

二、item布局match_parent属性失效问题

如果大家使用的是LinearLayoutMananger,并且在Adapter中创建item view使用的是如下的方法:

view =mInflater.inflate(R.layout.divider, null);

那么就会导致item无法居中显示,因为inflater在inflate一个xml时,需要知道parent的类型,才能生成对应的LayoutParams,才可以把xml根节点的attrs(如layout_width)读进去。所以需要使用如下代码:

view =mInflater.inflate(R.layout.divider, parent, false);

那么如果你使用的是自定义view,不是在adapter中使用Inflater进行布局创建,那么上面的方法就不好用了,此时,需要对item的根布局进行一次属性重设。如下:

    @Override    public CommonViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View view = new CustomView(mContext);        //在RecyclerView中,若使用的是LinearLayoutManager,由于view的创建没有用到parent,所以View中的match_parent属性会失效,所以在此显示设置一次,其他种类的LayoutManager不会出现此问题        view.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));        return new CommonViewHolder(view);    }

三、RecyclerView与各种异步图片加载框架不兼容,导致滑动item时,图片时有时无

如果在item view中存在NetWorkImageView(或者类似框架控件)时,偶尔会出现将一个条目刚刚滑动到看不见,然后将其拉回,其中的图片变为空白。

原因是,网络图片框架自定的ImageView中,覆写了onDetachedFromWindow方法,目的是为了在ImageView退出屏幕时及时回收Bitmap。而在RecyclerView中,当一个item被滑动到刚好看不见的位置时,触发了该item及其子View的onDetachedFromWindow,同样也就调用了setImageDrawable(null)。但是,RecyclerView.Adapter.onViewRecycled方法没有立刻被调用,而要等到继续滑动RecyclerView时才调用。也就是说,RecyclerView没有立即回收已经不在显示区域的item。如果此时将该item拉回,也不会再调用RecyclerView.Adapter.onBindViewHolder,也就是图片消失之后就不会再显示了,出现了开头提到的问题。

针对这个问题,自定义了一个ImageView,覆写onDetachFromWindown方法,让后通过Adapter中的onViewRecycled主动释放图片资源

public class CustomImageViewForRV extends ImageView {    private boolean isUsedInRV = true;    public CustomImageViewForRV(Context context) {        super(context);    }    @Override    protected void onDetachedFromWindow() {        if (!isUsedInRV) {            super.onDetachedFromWindow();        }    }}

Adapter中:

 @Override    public void onViewRecycled(RecyclerView.ViewHolder holder) {        if (holder != null) {            if (holder.itemView instanceof MyView) {                ((MyView) holder.itemView).release();            }        }    }

自定义ItemVview(MyView)中:

  public void release() {        if (mUserPic != null) {            //mUserPic就是CustomImageViewForRV            mUserPic.setImageDrawable(null);        }    }

四、notifyDataSetChanged时导致图片闪烁

这个问题比较好解决,一句代码,

mRecyclerViewAdapter.setHasStableIds(true);  

要注意,使用上述代码的话,Adapter中的getItemId要重写成如下,如果仍用super.getItemId(position),数据刷新会出错。

  @Override    public long getItemId(int position) {        return position;    }

从源码角度来看,相当于我们平时给ImageView和图片做了一个tag绑定,检测到是url没变时,不再重新加载图片,也就不用重新计算、绘制,这样就避免了图片闪烁

五、禁用RecyclerView item变化时的动画效果

两种方法:

1、全部禁用

 mRecyclerView.setItemAnimator(null);

2、将动画时长为0,从而达到取消动画的效果

mRecyclerView.getItemAnimator().setChangeDuration(0);mRecyclerView.getItemAnimator().setAddDuration(0);mRecyclerView.getItemAnimator().setMoveDuration(0);mRecyclerView.getItemAnimator().setRemoveDuration(0);

六、上拉加载时,报错

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 157(offset:157).state:588

这个问题在google官方话题单有提到,地址为 ISSUE 77846
我的解决方式是:

int preSize = mData.size();mData.addAll(newList);notifyItemRangeInserted(preSize, mData.size() - preSize);

七、ScrollView嵌套RecyclerView滑动卡顿的问题

recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()) {            /**             * 重写此方法解决ScrollView嵌套RecyclerView滑动卡顿的问题             */            @Override            public boolean canScrollVertically() {                return false;            }        });

八、RecyclerView某些情形下notifyDataSetChanged无效

解决方案链接

九、Android RecyclerView滚动定位问题
解决方案

0 0