为什么在RecyclerView.Adapter的onBindViewHolder中添加OnClickListener被认为是不好的做法?

Suj*_*dav 67 java performance android android-recyclerview

我有一个RecyclerView.Adapter类的以下代码,它工作正常:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.Viewholder> {

    private List<Information> items;
    private int itemLayout;

    public MyAdapter(List<Information> items, int itemLayout){
        this.items = items;
        this.itemLayout = itemLayout;
    }

    @Override
    public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
        return new Viewholder(v);
    }

    @Override
    public void onBindViewHolder(Viewholder holder, final int position) {
        Information item = items.get(position);
        holder.textView1.setText(item.Title);
        holder.textView2.setText(item.Date);

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(view.getContext(), "Recycle Click" + position, Toast.LENGTH_SHORT).show();
            }
        });

       holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
       @Override
       public boolean onLongClick(View v) {
          Toast.makeText(v.getContext(), "Recycle Click" + position, Toast.LENGTH_SHORT).show();
           return true;
       }
});
    }

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

    public class Viewholder extends RecyclerView.ViewHolder {
        public  TextView textView1;
        public TextView textView2;

        public Viewholder(View itemView) {
            super(itemView);
            textView1=(TextView) itemView.findViewById(R.id.text1);
            textView2 = (TextView) itemView.findViewById(R.id.date_row);

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我认为在onBindViewHolder方法中实现OnClickListener是不好的做法.为什么这是一种不好的做法,什么是更好的选择呢?

Ada*_*331 56

在ViewHolder中处理点击逻辑更好的原因是因为它允许更明确的点击侦听器.如Commonsware书中所述:

ListView行中的可点击小部件(如RatingBar)长期以来与行本身的点击事件冲突.获取可以单击的行,行内容也可以单击,有时会有点棘手.使用RecyclerView,您可以更明确地控制如何处理此类事物...因为您是设置所有点击处理逻辑的人.

通过使用ViewHolder模型,您可以在RecyclerView中获得比以前ListView中的点击处理更多的好处.我在一篇比较差异的博客文章中写到了这一点 - https://androidessence.com/android/recyclerview-vs-listview/

至于为什么它在ViewHolder中更好而不是in onBindViewHolder(),那是因为onBindViewHolder()为每个项目调用并设置click监听器是一个不必要的选项,当你可以在ViewHolder构造函数中调用它时重复一次.然后,如果您的点击响应取决于单击项目的位置,您只需getAdapterPosition()从ViewHolder中调用即可.是我给出的另一个答案,演示了如何OnClickListener在ViewHolder类中使用from.

  • 为避免不必要的点击监听器设置得到它!但是我们可以像Brucelet建议的那样在onCreateViewHolder()中实现它(见下面的答案). (2认同)

Bru*_*let 13

onCreateViewHolder()方法将被称为第一数次ViewHolder,需要每一个viewType.onBindViewHolder()每当新项目滚动到视图中或者其数据发生更改时,都会调用该方法.您希望避免任何昂贵的操作,onBindViewHolder()因为它可能会减慢您的滚动速度.这不是一个值得关注的问题onCreateViewHolder().因此,创建像OnClickListeners in onCreateViewHolder()这样的东西通常更好,这样它们每个ViewHolder对象只发生一次.您可以getLayoutPosition()在侦听器内部调用以获取当前位置,而不是使用position提供的参数onBindViewHolder().


小智 11

每次将视图绑定到尚未看到的对象时,都会调用onBindViewHolder方法.每次你都会添加新的听众.你应该这样做

@Override
public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) {
     View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
     final ViewHolder holder = new ViewHolder(v);

     holder.itemView.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
             Log.d(TAG, "position = " + holder.getAdapterPosition());
         }
     });
     return holder;
}
Run Code Online (Sandbox Code Playgroud)


小智 6

Pavel 提供了很好的代码示例,除了最后一行。您应该返回创建的持有人。不是新的Viewholder(v)。

@Override
public Viewholder onCreateViewHolder(ViewGroup parent, int viewType) {
     View v = LayoutInflater.from(parent.getContext()).inflate(itemLayout, parent, false);
     final ViewHolder holder = new ViewHolder(v);

     holder.itemView.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
             Log.d(TAG, "position = " + holder.getAdapterPosition());
         }
     });
     return holder;
}
Run Code Online (Sandbox Code Playgroud)