资讯专栏INFORMATION COLUMN

Android RecyclerView中的ViewHolder

bingchen / 2341人阅读

摘要:在使用提供的组件以列表的格式显示数据时,使用过组件和组件。当我们自定义一个时,继承了的一个内部类可以看到,内部已经帮我们定义好了抽象类,当我们自定义时,需要定义好要继承的类。

在使用android提供的组件以列表的格式显示数据时,使用过ListView组件和RecyclerView组件。目前一般推荐使用RecyclerView,因为RecyclerView本身的缓存和效率比ListView高,且支持灵活的布局方式,所以会被大家采用。相信大家在使用ListView时,如果要显示的数据多,肯定多会想到优化Adaper的getView()方法,下面给出一个例子:

public class UsersAdapter extends ArrayAdapter {

    private static class ViewHolder {
        TextView name;
        TextView home;
    }

    public UsersAdapter(Context context, ArrayList users) {
       super(context, R.layout.item_user, users);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       User user = getItem(position);    
       ViewHolder viewHolder;
       if (convertView == null) {
          viewHolder = new ViewHolder();
          LayoutInflater inflater = LayoutInflater.from(getContext());
          convertView = inflater.inflate(R.layout.item_user, parent, false);
          viewHolder.name = (TextView) convertView.findViewById(R.id.tvName);
          viewHolder.home = (TextView)convertView.findViewById(R.id.tvHome);
          convertView.setTag(viewHolder);
       } else {
           viewHolder = (ViewHolder) convertView.getTag();
       }
       viewHolder.name.setText(user.name);
       viewHolder.home.setText(user.hometown);
       return convertView;
   }
}

在这边,我们在ListView需要用到的Adapter中定义了一个内部类ViewHolder,它存储了我们要加载的view的所有子view结构,如果这个view已经被加载过只是暂时被回收, 当需要再次展示的话我们就不需要重新加载整个view,也不需要通过findViewById()来寻找要加载的view的子view,可以直接找到这个view,将要展示的数据设置即可返回显示。

但是在RecyclerView中,我们并不需要做这么多,我们先看一个RecyclerView的简单使用步骤:

定义一个RecyclerView的布局文件以及要展示的item的布局文件


   
    
    









定义一个adapter

public class ClassAdapter extends RecyclerView.Adapter {

private List classVOs;

static class ClassViewHolder extends RecyclerView.ViewHolder {

    View classView;
    TextView className;

    public ClassViewHolder(View itemView) {
        super(itemView);
        classView = itemView;
        className = (TextView) itemView.findViewById(R.id.t_class_name);
    }
}

public ClassAdapter(List classVOs){
    this.classVOs = classVOs;
}

@Override
public ClassViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragement_class_item, null, false);
    final ClassViewHolder holder = new ClassViewHolder(view);
    holder.classView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            int position = holder.getAdapterPosition();
            ClassVO classVO = classVOs.get(position);
            Toast.makeText(view.getContext(), "you click class "+classVO.getId(), Toast.LENGTH_SHORT).show();
        }
    });
    return holder;
}

@Override
public void onBindViewHolder(ClassViewHolder holder, int position) {
    ClassVO classVO = classVOs.get(position);
    holder.className.setText(classVO.getName());
}

@Override
public int getItemCount() {
    return classVOs.size();
}

}

设置RecyclerView的布局和adapter

recyclerView = (RecyclerView) classListView.findViewById(R.id.t_classList);
layoutManager = new LinearLayoutManager(this.getContext());
recyclerView.setLayoutManager(layoutManager);
if (classVOs!=null){
    adapter = new ClassAdapter(classVOs);
}
recyclerView.setAdapter(adapter);

既然我们要说的是RecyclerView中的ViewHolder,但是我们的使用步骤中并没有多带带提出ViewHolder,因为在我们上面说的使用步骤的第二步———“定义一个adapter”,就涉及到ViewHolder。
当我们自定义一个adapter时,继承了RecyclerView的一个内部类:

 /**
     * Base class for an Adapter
     *
     * 

Adapters provide a binding from an app-specific data set to views that are displayed * within a {@link RecyclerView}.

*/ public static abstract class Adapter { private final AdapterDataObservable mObservable = new AdapterDataObservable(); private boolean mHasStableIds = false; /** * Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent * an item. *

* This new ViewHolder should be constructed with a new View that can represent the items * of the given type. You can either create a new View manually or inflate it from an XML * layout file. *

* The new ViewHolder will be used to display items of the adapter using * {@link #onBindViewHolder(ViewHolder, int, List)}. Since it will be re-used to display * different items in the data set, it is a good idea to cache references to sub views of * the View to avoid unnecessary {@link View#findViewById(int)} calls. * * @param parent The ViewGroup into which the new View will be added after it is bound to * an adapter position. * @param viewType The view type of the new View. * * @return A new ViewHolder that holds a View of the given view type. * @see #getItemViewType(int) * @see #onBindViewHolder(ViewHolder, int) */ public abstract VH onCreateViewHolder(ViewGroup parent, int viewType); /** * Called by RecyclerView to display the data at the specified position. This method should * update the contents of the {@link ViewHolder#itemView} to reflect the item at the given * position. *

* Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method * again if the position of the item changes in the data set unless the item itself is * invalidated or the new position cannot be determined. For this reason, you should only * use the position parameter while acquiring the related data item inside * this method and should not keep a copy of it. If you need the position of an item later * on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will * have the updated adapter position. * * Override {@link #onBindViewHolder(ViewHolder, int, List)} instead if Adapter can * handle efficient partial bind. * * @param holder The ViewHolder which should be updated to represent the contents of the * item at the given position in the data set. * @param position The position of the item within the adapter"s data set. */ public abstract void onBindViewHolder(VH holder, int position); /** * Called by RecyclerView to display the data at the specified position. This method * should update the contents of the {@link ViewHolder#itemView} to reflect the item at * the given position. *

* Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method * again if the position of the item changes in the data set unless the item itself is * invalidated or the new position cannot be determined. For this reason, you should only * use the position parameter while acquiring the related data item inside * this method and should not keep a copy of it. If you need the position of an item later * on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will * have the updated adapter position. *

* Partial bind vs full bind: *

* The payloads parameter is a merge list from {@link #notifyItemChanged(int, Object)} or * {@link #notifyItemRangeChanged(int, int, Object)}. If the payloads list is not empty, * the ViewHolder is currently bound to old data and Adapter may run an efficient partial * update using the payload info. If the payload is empty, Adapter must run a full bind. * Adapter should not assume that the payload passed in notify methods will be received by * onBindViewHolder(). For example when the view is not attached to the screen, the * payload in notifyItemChange() will be simply dropped. * * @param holder The ViewHolder which should be updated to represent the contents of the * item at the given position in the data set. * @param position The position of the item within the adapter"s data set. * @param payloads A non-null list of merged payloads. Can be empty list if requires full * update. */

可以看到,RecyclerView内部已经帮我们定义好了ViewHolder抽象类,当我们自定义Adapter时,需要定义好要继承ViewHolder的类(Adapter)。

ViewHolder的作用我们在上文介绍使使用ListView时已经说到,简而言之就是提高消息,下面我们看一看源码中对ViewHolder的介绍:

/**
     * A ViewHolder describes an item view and metadata about its place within the RecyclerView.
     *
     * 

{@link Adapter} implementations should subclass ViewHolder and add fields for caching * potentially expensive {@link View#findViewById(int)} results.

* *

While {@link LayoutParams} belong to the {@link LayoutManager}, * {@link ViewHolder ViewHolders} belong to the adapter. Adapters should feel free to use * their own custom ViewHolder implementations to store data that makes binding view contents * easier. Implementations should assume that individual item views will hold strong references * to ViewHolder objects and that RecyclerView instances may hold * strong references to extra off-screen item views for caching purposes

*/ public static abstract class ViewHolder { ...... }

可以看出两点重要的地方:

Adapter implementations should subclass ViewHolder and add fields for caching potentially expensive {@link View#findViewById(int)} results(adapter应当拥有ViewHolder的子类,并且ViewHolder内部应当存储一些子view,避免时间代价很大的findViewById操作)

Adapters should feel free to use their own custom ViewHolder implementations to store data that makes binding view content easier

其RecyclerView内部定义的ViewHolder类包含很多复杂的属性,内部使用场景也有很多,而我们经常使用的也就是onCreateViewHolder()方法和onBindViewHolder()方法,onCreateViewHolder()方法在RecyclerView需要一个新类型。item的ViewHolder时调用来创建一个ViewHolder,而onBindViewHolder()方法则当RecyclerView需要在特定位置的item展示数据时调用。

参考文章:

http://www.jianshu.com/p/d7ec...

https://guides.codepath.com/a...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/13741.html

相关文章

  • Android Material Design系列之RecyclerView和CardView

    摘要:为用于显示复杂视图的新增。建议大家参考上拉更多具体使用不讲了,今天我们顺便讲一下如何在加上拉更多的效果吧,下拉刷新我们使用的效果就行。因为我看市面上目前大部分的都是这样做的,下拉刷新用的效果,自己在上添加上拉更多。 去年很早之前,我就讲解过RecyclerView的使用,今天我们就在讲解CardView的时候,顺便再把RecyclerView同时讲解一下。RecyclerView、Ca...

    codeKK 评论0 收藏0
  • Android Material Design系列之RecyclerView和CardView

    摘要:为用于显示复杂视图的新增。建议大家参考上拉更多具体使用不讲了,今天我们顺便讲一下如何在加上拉更多的效果吧,下拉刷新我们使用的效果就行。因为我看市面上目前大部分的都是这样做的,下拉刷新用的效果,自己在上添加上拉更多。 去年很早之前,我就讲解过RecyclerView的使用,今天我们就在讲解CardView的时候,顺便再把RecyclerView同时讲解一下。RecyclerView、Ca...

    WrBug 评论0 收藏0
  • Android开发学习之RecyclerView

    摘要:在中添加依赖注意依赖版本号布局文件引入泛型类型布局适配器适配器保存的数据容器类,容纳构造函数初始化适配器创建绑定数据到返回子项个数配置并使用使用布局管理器大功告成,运行截图1、在app/build.gradle中添加RecyclerView依赖 1 implementation com.android.support:recyclerview-v7:28.0.0 注意依赖版本号 2、布局...

    番茄西红柿 评论0 收藏0
  • RecyclerView详细解释

    摘要:详细解释简单介绍是一个高度的解耦,异常的灵活的,通过设置它提供的不同,实现令人瞠目的效果。能够显示数据还离不开另外两个类的支持子类和子类。会找到目标位置的数据并绑定到的视图上。整个过程执行完毕,就能在屏幕上显示列表项了。 RecyclerView详细解释 RecyclerView简单介绍 RecyclerView是一个高度的解耦,异常的灵活的View,通过设置它提供的不同LayoutM...

    Ashin 评论0 收藏0
  • android RecyclerView

    摘要:如果想指定可以拖拽,需要重写返回,在的长按监听事件里调用开启拖拽是否支持滑动操作,默认是支持返回。实例分别把中间所有的的位置重新交换滑动时改变的透明度添加接口指定页卡滑动一次能滑动多页一次只能滑动一页引用 在项目的build.gradle添加依赖 compile com.android.support:recyclerview-v7:23.4.0 RecyclierView使用的基本方法...

    番茄西红柿 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<