Ich habe den folgenden Code für eine RecyclerView.Adapter
Klasse und es funktioniert gut:
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);
}
}
}
Ich halte es jedoch für eine schlechte Praxis, den OnClickListener in der onBindViewHolder
Methode zu implementieren . Warum ist diese schlechte Praxis und was ist eine bessere Alternative?
quelle
onCreateViewHolder()
es nur einmal aufgerufen wird (pro ViewHolder). Ob Sie es also in Ihrem ViewHolder-Konstruktor oder in implementieren,onCreateViewHolder()
liegt ganz bei Ihnen. Ich habe mir angewöhnt, es in die VH aufzunehmen, aber Sie sollten das tun, was Ihrer Meinung nach am besten lesbar ist und Ihnen in Zukunft beim Verständnis helfen wird. Vermeiden Sie einfachonBindViewHolder()
aus Leistungsgründen wie von Brucelet vorgeschlagen.onCreateViewHolder()
eher in als imViewHolder
Konstruktor, damit ich meineViewHolder
Klasse erstellen kannstatic
und keinen Verweis auf den Adapter an den übergeben mussViewHolder
. Aber letztendlich ist es meistens eine Stilwahl, da es eine Eins-zu-Eins-Entsprechung zwischenonCreateViewHolder()
und geben solltenew ViewHolder()
.getAdapterPosition()
aus dem ViewHolder heraus anrufen. Siehe die Antwort, auf die ich verlinkt habe. Es sei denn, ich habe falsch verstanden, was du meintest?Die Methode
onBindViewHolder
wird jedes Mal aufgerufen, wenn Sie Ihre Ansicht mit einem Objekt verknüpfen, das gerade nicht gesehen wurde. Und jedes Mal fügen Sie einen neuen Listener hinzu.Stattdessen sollten Sie den Klick-Listener anhängen
onCreateViewHolder
Beispiel:
@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; }
quelle
Die
onCreateViewHolder()
Methode wird das erste Mal aufgerufen, wennViewHolder
jeweils a benötigt wirdviewType
. DieonBindViewHolder()
Methode wird jedes Mal aufgerufen, wenn ein neues Element in die Ansicht gescrollt wird oder wenn sich die Daten ändern. Sie möchten teure Vorgänge vermeiden,onBindViewHolder()
da dies das Scrollen verlangsamen kann. Dies ist in weniger besorgniserregendonCreateViewHolder()
. Daher ist es im Allgemeinen besser, Dinge wieOnClickListener
sonCreateViewHolder()
so zu erstellen , dass sie nur einmal proViewHolder
Objekt vorkommen. Sie könnengetLayoutPosition()
den Listener anrufen , um die aktuelle Position abzurufen, anstatt das angegebeneposition
Argument zu übernehmenonBindViewHolder()
.quelle
Pavel lieferte ein großartiges Codebeispiel mit Ausnahme einer Zeile am Ende. Sie sollten den erstellten Inhaber zurückgeben. Nicht der neue 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; }
quelle
Per https://developer.android.com/topic/performance/vitals/render ,
onBindViewHolder
sollte seine Arbeit in „viel weniger als eine Millisekunde“ tut langsames Rendering zu verhindern.quelle
So implementiere ich die Klicks meiner Schaltflächen in meinem ViewHolder anstelle meines onBindViewHolder. Dieses Beispiel zeigt, wie Sie mehr als eine Schaltfläche mit einer Schnittstelle verbinden, die beim Auffüllen von Zeilen nicht mehr Objekte generiert.
Das Beispiel ist auf Spanisch und auf Kotlin , aber ich bin sicher, dass die Logik verständlich ist.
/** * Created by Gastón Saillén on 26 December 2019 */ class DondeComprarRecyclerAdapter(val context:Context,itemListener:RecyclerViewClickListener):RecyclerView.Adapter<BaseViewHolder<*>>() { interface RecyclerViewClickListener { fun comoLlegarOnClick(v: View?, position: Int) fun whatsappOnClick(v:View?,position: Int) } companion object{ var itemClickListener: RecyclerViewClickListener? = null } init { itemClickListener = itemListener } private var adapterDataList = mutableListOf<Institucion>() fun setData(institucionesList:MutableList<Institucion>){ this.adapterDataList = institucionesList } fun getItemAt(position:Int):Institucion = adapterDataList[position] override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> { val view = LayoutInflater.from(context) .inflate(R.layout.dondecomprar_row, parent, false) return PuntosDeVentaViewHolder(view) } override fun getItemCount(): Int { return if(adapterDataList.size > 0) adapterDataList.size else 0 } override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) { val element = adapterDataList[position] when(holder){ is PuntosDeVentaViewHolder -> holder.bind(element) else -> throw IllegalArgumentException() } } inner class PuntosDeVentaViewHolder(itemView: View):BaseViewHolder<Institucion>(itemView),View.OnClickListener{ override fun bind(item: Institucion) { itemView.txtTitleDondeComprar.text = item.titulo itemView.txtDireccionDondeComprar.text = item.direccion itemView.txtHorarioAtencDondeComprar.text = item.horario itemView.btnComoLlegar.setOnClickListener(this) itemView.btnWhatsapp.setOnClickListener(this) } override fun onClick(v: View?) { when(v!!.id){ R.id.btnComoLlegar -> { itemClickListener?.comoLlegarOnClick(v, adapterPosition) } R.id.btnWhatsapp -> { itemClickListener?.whatsappOnClick(v,adapterPosition) } } } } }
Und der BaseViewHolder, der in jedem Adapter implementiert werden soll
/** * Created by Gastón Saillén on 27 December 2019 */ abstract class BaseViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) { abstract fun bind(item: T) }
quelle
Ich hatte ein kleines Problem, das ich in den Antworten teilen möchte, wenn auch jemand anderes damit konfrontiert ist. Ich hatte Bild und Text in Recycleview als Cardview anzuzeigen. Daher sollte mein Code gemäß den Empfehlungen wie folgt lauten.
@Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.books_item_row, parent, false); final MyViewHolder holder = new MyViewHolder(itemView); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getActivity(), "Recycle Click", Toast.LENGTH_LONG).show(); } }); return holder; }
Wenn ich jedoch in der Recycling-Ansicht auf die Karte klicke, funktioniert sie nicht, da sich die Elementansicht unter dem Bild befindet. Daher habe ich den Code wie folgt leicht geändert.
@Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.books_item_row, parent, false); final MyViewHolder holder = new MyViewHolder(itemView); holder.thumbnail.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Log.d(TAG, "position = " + holder.getAdapterPosition()); Toast.makeText(getActivity(), "Recycle Click", Toast.LENGTH_LONG).show(); } }); return holder; }
Das heißt, anstelle der Objektansicht muss die Person jetzt auf die Miniaturansicht oder das Bild klicken.
quelle
Sie können dies auch auf diese Weise tun.
MainActivity-Klasse
In dieser Vielzahl von Schnittstellentriggern können Sie dies erreichen ...
Adapterklasse
quelle