RecyclerView,你一定要这么用!!

RecyclerView的最佳使用方案

RecyclerView已经广为人知,并且别大家所使用。然而在使用的过程中,有一些却不是RecyclerView开发者希望使用的

ViewHolder


你怎么使用你的ViewHolder?

//定义
 class ViewHolder {
        TextView title;
        TextView body;
        ImageView icon;
    }

   //adapter中使用
   public void onBindViewHolder(ViewHolder vh, int pos)
    {
        Item item = items.get(pos);
        title.setText(item.getTitle());
        body.setText(item.getBody());
        imageLoader.loadImage(icon, item.IconUrl());
    }

不知道你是不是这么写的,反正我看到的代码,99%都是这么撸出来的。
在这种写法中,我们需要获取到ViewHolder,然后获取到Item数据,然后将二者进行绑定。但是这二者其实是没有任何关系的。
最佳写作方法是啥呢?这可不是我说的,是Yigit这么说的,别赖我。

    //定义
    class ViewHolder {
        ...
        public bindTo(Item item, ImageLoader imageLoader) {
            title.setText(item.getTitle());
            body.setText(item.getBody());
            imageLoader.loadImage(icon, item.IconUrl());
         }
    }
    //adatper中调用
    public void onBindViewHolder(ViewHolder vh, int position) {
        vh.bindTo(items.get(position), mImageLoader);
    }

在这种写法中,我们在ViewHolder中进行View的定义,并且生成一个绑定方法bindTo(),通过这个方法,我们知道,我们显示这个ViewHolder,需要一个Item类以及一个ImageLoader,至于这两个参数如何和ViewHolder进行数据的关联,交给ViewHolder进行处理。
而且,这样你的ViewHolder也可以在应用的其他地方进行使用,就像一个Presenter一样。你的ViewHolder内部进行了很好的封装。

View Types


在我们进行多条目的显示时,一般我们都会使用到ViewTypes。但是如何才能进行更好的代码书写呢?
你是如何做的呢?

@Override
public int getItemViewType(int position) {
    User user = mItems.get(position);
    if (user.isPremium()) {
        return TYPE_PREMIUM;
    }
    return TYPE_BASIC;
}

然后再根据不同的类型,绘制不同的布局,生成ViewHolder。

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view;
    switch (viewType) {
        case TYPE_PREMIUM:
            view = mLayoutInflater.inflate(R.layout.premium, parent,false);
            break;
        case TYPE_BASIC:
            view = mLayoutInflater.inflate(R.layout.basic, parent,false);
            break;
    }
    return new UserViewHolder(view);
}

如果只有两种类型,很OK,但是如果有很多种类型呢?我们就需要在getItemViewType中的类型和onCreateViewHolder中的类型进行好好的对应了。一个不小心,就over叻。
其实,我们可以耍个小滑头。

@Override
public int getItemViewType(int position) {
    User user = mItems.get(position);
    if (user.isPremium()) {
        return R.layout.premium;
    }
    return R.layout.basic;
}


public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view;
    view = mLayoutInflater.inflate(viewType, parent,false);
    return new UserViewHolder(view);
}

我们可以将布局文件的id进行返回,我们知道,布局文件的id是系统生成的,而且是唯一的。一旦你这么做了,我们看到,在onCreateViewHolder中,我们不需要再重复处理复杂的逻辑。

OnClickListener


众所周知,RecyclerView中,去掉了setOnItemClicker方法,而我们一般通过自己定义一个点击事件的回调进行处理。

public void onBindViewHolder(ViewHolder vh,final int position) {
    vh.likeButton.setOnClickListener = new OnClickListener() {
        items[position].liked = true;
        notifyItemChanged(position);
    }
}

这块代码段估计是我们经常写的代码了,其实它是存在问题的。
1.当我们每次调用数据和viewholder进行绑定的时候,都重新生成了一个OnClickListener()。
2.在ListView中,我们这样使用postion是没有任何问题的,但是在Recyclerview中,postion并不是final类型,它是可能会该病的。

谷歌更加推荐我们在ViewHolder生成的时候进行点击事件的绑定。代码如下:

    public onCreateViewHolder(...) {
        final ViewHolder vh = ....;
        myViewHolder.itemView.setOnClickListener({
            int pos = vh.getAdapterPosition();
            if (pos != NO_POSITION) {
                 items[position].liked = true;
                 notifyItemChanged(position);
            }
        });
    }
}

其中,getAdapterPosition()这个方法是谷歌最推行的获取ViewHolder在adapter中的位置的方法。
这个方法中,还需要注意的一点,是NO_POSITION(-1)的判断,由于RecyclerView是异步,如果我们将所有的items都删除了,而Recyclerview没有重新进行绘制,那么当我们再次点击条目的时候,获取到的postion将会是-1。

先记录这么些吧。关于Recyclerview的一些官方推荐写法和介绍,以后慢慢记录。

发布了16 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/adfghjkl/article/details/53818094