我有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);
}
}
}
但是,我认为在onBindViewHolder
方法中实现OnClickListener是不好的做法。为什么这是一种不好的做法,什么是更好的选择呢?
答案 0 :(得分:53)
在ViewHolder中处理点击逻辑更好的原因是因为它允许更明确的点击侦听器。正如Commonsware书中所表达的那样:
ListView行中的可点击小部件(如RatingBar)长期以来与行本身的点击事件冲突。获取可以单击的行,行内容也可以单击,有时会有点棘手。使用RecyclerView,您可以更明确地控制如何处理这类事情......因为您是设置所有点击处理逻辑的人。
通过使用ViewHolder模型,您可以在RecyclerView中获得比以前ListView中的点击处理更多的好处。我在博客文章中写了这篇文章,比较了差异 - https://androidessence.com/android/recyclerview-vs-listview/
至于为什么在ViewHolder而不是onBindViewHolder()
中更好,这是因为为每个项目调用onBindViewHolder()
并设置点击监听器是一个不必要的选项,可以重复在ViewHolder构造函数中调用一次。然后,如果您的点击响应取决于所点击项目的位置,您只需从ViewHolder中调用getAdapterPosition()
即可。 Here是我给出的另一个答案,演示了如何在ViewHolder类中使用OnClickListener
。
答案 1 :(得分:13)
onCreateViewHolder()
方法会在前几次被调用,每个ViewHolder
需要viewType
。每次新项目滚动到视图中或者其数据发生更改时,都会调用onBindViewHolder()
方法。您希望避免onBindViewHolder()
中的任何昂贵操作,因为它会降低您的滚动速度。这在onCreateViewHolder()
中不太重要。因此,在OnClickListener
中创建onCreateViewHolder()
之类的内容通常会更好,这样它们每ViewHolder
个对象只会发生一次。您可以在侦听器中调用getLayoutPosition()
以获取当前位置,而不是将position
参数提供给onBindViewHolder()
。
答案 2 :(得分:8)
每次将视图绑定到尚未看到的对象时,都会调用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;
}
答案 3 :(得分:5)
Pavel provided伟大的代码示例,除了最后一行。你应该返回创建的持有人。不是新的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;
}
答案 4 :(得分:0)
每https://developer.android.com/topic/performance/vitals/render,onBindViewHolder
应该在“少于一毫秒的时间内”完成工作,以防止缓慢渲染。
答案 5 :(得分:0)
这是我在ViewHolder中而不是onBindViewHolder中实现按钮单击的方式。此示例显示了如何将多个按钮与一个接口绑定,该接口在填充行时不会生成更多对象。
该示例使用西班牙语和科特林,但是我确信逻辑是可以理解的。
/**
* 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)
}
}
}
}
}
以及要在每个适配器中实现的BaseViewHolder
/**
* Created by Gastón Saillén on 27 December 2019
*/
abstract class BaseViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(item: T)
}
答案 6 :(得分:0)
我遇到了一个小问题,如果其他人也遇到这个问题,我想在答案中分享。 我有图像和文本以Cardview的形式显示在Recycleview中。因此,根据建议,我的代码应如下所示。
@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;
}
但是,当我在回收视图中单击该卡片时,它将不起作用,因为itemview位于图像下方。因此,我对代码进行了如下更改。
@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;
}
即人现在必须单击缩略图或图像,而不是itemview。
答案 7 :(得分:0)