【发布时间】:2019-11-18 16:47:47
【问题描述】:
我正在尝试在我的应用中实现 RecyclerView。这是我的适配器类:
public class AdapterItemsList extends RecyclerView.Adapter<AdapterItemsList.ViewHolderItems>
{
private ArrayList<CItem> items;
public AdapterItemsList(ArrayList<CItem> items)
{
this.items = items;
}
@NonNull
@Override
public ViewHolderItems onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_counter, null, false);
return new ViewHolderItems(view);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolderItems holder, final int position)
{
holder.asignarDatos(items.get(holder.getAdapterPosition()));
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
//deleteSelectedItem() method gonna be here
Toast.makeText(view.getContext(), String.valueOf(holder.getAdapterPosition())
, Toast.LENGTH_SHORT).show();
return false;
}
});
holder.counterAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString());
auxInteger += 1;
holder.itemNumber.setText(auxInteger.toString());
items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString()));
}
});
holder.counterSubtract.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString());
if (auxInteger > 0)
{
auxInteger -= 1;
holder.itemNumber.setText(auxInteger.toString());
items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString()));
}
}
});
}
@Override
public int getItemCount()
{
return items.size();
}
public class ViewHolderItems extends RecyclerView.ViewHolder
{
TextView itemName;
TextView itemNumber;
Button counterAdd;
Button counterSubtract;
public ViewHolderItems(View itemView)
{
super(itemView);
itemName = (TextView) itemView.findViewById(R.id.textViewItemCounterName);
itemNumber = (TextView) itemView.findViewById(R.id.textViewItemCounterNumber);
counterAdd = (Button) itemView.findViewById(R.id.buttonItemCounterAdd);
counterSubtract = (Button) itemView.findViewById(R.id.buttonItemCounterSubtract);
}
public void asignarDatos(CItem item)
{
itemName.setText(item.getObjectName());
itemNumber.setText(item.getObjectNumber().toString());
}
}
}
“创建”适配器的代码:
private void CreateAdapter() {
recyclerViewItems.setAdapter(null);
items.clear();
//I dont post the code, but this just gets data from a SQLite database and populate "items".
LoadClientsList();
final AdapterItemsList adapter = new AdapterItemsList(items);
recyclerViewItems.setAdapter(adapter);
}
如您所见,我从不使用“实现 View.OnLongClickListener”或类似的东西,但我只是在 onBindViewHolder 中设置了 OnClickListener。现在里面有一个“Toast”(当我测试应用程序时它看起来很好),但稍后应该有我的“删除项目”对话框,它会给用户更改接受或取消(一个常见的对话框) .如果用户按“接受”,那么我将从列表中删除该项目。
我承认,我不是 Android 或 Java Ninja,所以我知道可能存在可怕的错误。但问题是,该应用程序现在正在运行(当我长按一个项目时,Toast 会正确显示),但事实上我从不使用“实现”,而我看到每个人都在与 RecyclerViews 和适配器相关的 StackOverflow 问题中这样做,让我觉得我犯了(几个)严重错误。
我可以承认,因为我不是 Java 基础知识的大师(已经使用 COBOL 工作了几年,我记得 OOP 几乎是 NULL),我不知道我的错误在哪里,但仍然非常感谢任何帮助。
谢谢!
更新: 好的,我正在更改我的代码,现在如下所示:
public class AdapterItemsList extends RecyclerView.Adapter<AdapterItemsList.ViewHolderItems> implements View.OnClickListener { private ArrayList<CItem> items; /* Added this */ private View.OnClickListener listener; public AdapterItemsList(ArrayList<CItem> items) { this.items = items; } @NonNull @Override public ViewHolderItems onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_counter, null, false); /* Added this */ view.setOnClickListener(this); return new ViewHolderItems(view); } @Override public void onBindViewHolder(@NonNull final ViewHolderItems holder, final int position) { holder.asignarDatos(items.get(holder.getAdapterPosition())); holder.counterAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString()); auxInteger += 1; holder.itemNumber.setText(auxInteger.toString()); items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString())); } }); holder.counterSubtract.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Integer auxInteger = Integer.parseInt(holder.itemNumber.getText().toString()); if (auxInteger > 0) { auxInteger -= 1; holder.itemNumber.setText(auxInteger.toString()); items.get(holder.getAdapterPosition()).setObjectNumber(Integer.parseInt(holder.itemNumber.getText().toString())); } } }); } @Override public int getItemCount() { [...] } /* Added this */ public void setOnClickListener(View.OnClickListener listener) { this.listener = listener; } /* Added this */ @Override public void onClick(View view) { if (listener != null) { listener.onClick(view); } } public class ViewHolderItems extends RecyclerView.ViewHolder { [...] } }
我创建适配器的代码:
private void CreateAdapter() { recyclerViewItems.setAdapter(null); items.clear(); LoadClientsList(); final AdapterItemsList adapter = new AdapterItemsList(items); /* Added this */ adapter.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(getApplicationContext(), String.valueOf(recyclerViewItems.getChildAdapterPosition(view)), Toast.LENGTH_SHORT).show(); } }); recyclerViewItems.setAdapter(adapter); }
“recyclerViewItems.getChildAdapterPosition(view)”终于解决了我的问题(之前没有提到,但这就是我将“setOnClick...”放在onBindViewHolder方法中的原因,只是因为我需要的位置按下的项目,我不知道如何访问它)。 所以现在我在创建适配器时设置监听器,而不是在绑定视图持有者时设置监听器,我想这样会更好。 不过,我没有更改“holder.counterAdd.setOnClickListener”和“holder.counterSubtract.setOnClickListener”行,因为我认为它们必须在onBindViewHolder方法中,但我想我还是错了。
【问题讨论】:
-
您的解决方案比
implements View.OnClickListener更好,因为您为每个项目分配了一个实现View.OnClickListner接口的匿名类实例。 -
更糟糕的是,监听器被设置在
onBindViewHolder中,这将被调用多次。每次用户滚动时,onBindViewHolder会为每个可见项目调用,然后是一些。所以,这个例子不仅是为固定数量的可见项目创建匿名对象,而且每次调用onBindViewHolder -
@sonnet 听起来很糟糕,因为你这样提到它。我会进行更多调查,看看如何使用“工具”。
-
将“setOnClickListener”放入“onCreateViewHolder”方法会改变什么吗?至少它不会被多次调用,还是我错了?
-
现在它可能正在泄漏调用此
CreateAdapter()的任何位置的上下文。因为匿名类持有对其父类的引用(参见stackoverflow.com/questions/5054360/…)编辑:这就是@MikeM.- 前一个没有泄漏上下文。
标签: android android-recyclerview android-adapter android-viewholder