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);
}
}
}
ただし、OnClickListenerをonBindViewHolder
メソッドに実装するのは悪い習慣だと思います。なぜこれが悪い習慣であり、より良い代替策は何ですか?
ViewHolder内でクリックロジックを処理する方が良い理由は、より明示的なクリックリスナーを許可するためです。 Commonswareブックに記載されているとおり:
ListView行のRatingBarなどのクリック可能なウィジェットは、行自体のクリックイベントと長い間競合していました。クリック可能な行と、クリック可能な行のコンテンツを取得することは、時々少し注意が必要です。 RecyclerViewを使用すると、この種の処理方法をより明確に制御できます。これは、クリック時のすべての処理ロジックを設定しているためです。
ViewHolderモデルを使用することで、RecyclerViewのクリック処理で、以前のListViewよりも多くの利点を得ることができます。これについては、ブログ投稿で違いを比較して書いています- https://androidessence.com/recyclerview-vs-listview
onBindViewHolder()
ではなくViewHolderの方が優れている理由は、onBindViewHolder()
が各アイテムごとに呼び出され、クリックリスナーの設定は、一度呼び出すことができるときに繰り返す不要なオプションだからです。 ViewHolderコンストラクターで。次に、クリックしたアイテムの位置に応じてクリックが応答する場合、ViewHolder内からgetAdapterPosition()
を呼び出すだけです。 Here は、ViewHolderクラス内からOnClickListener
を使用する方法を示す別の回答です。
onCreateViewHolder()
メソッドは、各ViewHolder
にviewType
が必要な最初の数回呼び出されます。 onBindViewHolder()
メソッドは、新しいアイテムがスクロールして表示されるか、データが変更されるたびに呼び出されます。スクロールが遅くなる可能性があるため、onBindViewHolder()
での高価な操作を避けたい。これは、onCreateViewHolder()
の問題ではありません。したがって、OnClickListener
オブジェクトごとに1回だけ発生するように、onCreateViewHolder()
にViewHolder
sのようなものを作成することをお勧めします。 getLayoutPosition()
に提供されたposition
引数を取るのではなく、リスナー内でonBindViewHolder()
を呼び出して現在の位置を取得できます。
表示されていないオブジェクトにビューをバインドするたびに、メソッドonBindViewHolder
が呼び出されます。そして、新しいリスナーを追加するたびに。
代わりに、クリックリスナーをonCreateViewHolder
にアタッチする必要があります
例:
@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;
}
Pavel 提供 最後の1行を除く素晴らしいコード例。作成したホルダーを返却する必要があります。新しい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;
}
https://developer.Android.com/topic/performance/vitals/render 、onBindViewHolder
は、レンダリングが遅くならないように「1ミリ秒未満」で作業を行う必要があります。
RecyclerView:バインドに時間がかかりすぎる
バインド(つまり、onBindViewHolder(VH、int))は非常にシンプルで、最も複雑なアイテムを除くすべてのアイテムについて1ミリ秒未満で処理する必要があります。アダプタの内部アイテムデータからPOJOアイテムを取得し、ViewHolderのビューでセッターを呼び出すだけです。 RV OnBindViewに時間がかかっている場合は、バインドコードで最小限の作業を行っていることを確認してください。