这是在Android中实现RecyclerView的错误方法吗?
我正在尝试在我的应用程序中实现一个RecyclerView。这是我的适配器类:这是在Android中实现RecyclerView的错误方法吗?,android,android-recyclerview,android-adapter,android-viewholder,Android,Android Recyclerview,Android Adapter,Android Viewholder,我正在尝试在我的应用程序中实现一个RecyclerView。这是我的适配器类: public class AdapterItemsList extends RecyclerView.Adapter<AdapterItemsList.ViewHolderItems> { private ArrayList<CItem> items; public AdapterItemsList(ArrayList<CItem> items) {
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());
}
}
}
如您所见,我从未使用“implements View.OnLongClickListener”或类似的东西,但我只是在onBindViewHolder中设置OnClickListener。现在里面有一个“Toast”(当我测试应用程序时,它看起来很好),但是稍后,应该会有我的“delete item”对话框,它会给用户提供接受或取消的更改(通常的对话框)。如果用户按“接受”,那么我将从列表中删除该项
我要承认,我不是安卓或Java忍者,所以我知道可能会有可怕的错误。但问题是,这个应用程序现在已经可以运行了(当我长按某个项目时,祝酒词显示正确),但我从来没有使用过“工具”,尽管我看到每个人都在使用与RecyclerViews和适配器相关的StackOverflow问题,但这一事实让我觉得我犯了(几个)严重错误
我可以承认,由于我不是Java基础知识的大师(我已经在COBOL工作了几年,对OOP的记忆几乎为空),我不知道我的错误在哪里,但仍然非常感谢任何帮助
谢谢你
更新: 好的,我正在更改代码,现在代码如下: “RecycleServiceItems.getChildAdapterPosition(view)”最终解决了我的问题(之前没有提到,但这正是我将“setOnClick…”放在onBindViewHolder方法中的原因,只是因为我需要按下项的位置,我不知道究竟如何访问它)。 因此,现在我在创建适配器时设置侦听器,而不是在绑定视图持有者时设置侦听器,我认为这样更好。
尽管如此,我还是没有更改“holder.counterAdd.setOnClickListener”和“holder.counterSubtract.setOnClickListener”行,因为我认为它们一定在onBindViewHolder方法中,但我想我在这一点上仍然是错的。我不同意关于您的问题的大多数评论,我认为您编写适配器的方式非常好。这并不完美,但是手动将
视图设置为没有问题。OnClickListener
到视图持有者中的一些(或多个)视图。事实上,这是谷歌推荐的做事方式
不过,我会做出一些改变。第一种方法是将click侦听器的声明移动到onCreateViewHolder()
方法中(将它们放在ViewHolder的构造函数中)。第二种方法是添加对NO_POSITION
的检查,以确保您能够处理项目已从适配器中删除但布局尚未重新计算的情况
以下是我的建议:
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);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
deleteItem();
return true;
}
});
counterAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
itemAdd();
}
});
counterSubtract.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
itemSubtract();
}
});
}
private void deleteItem() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
items.remove(position);
adapter.notifyItemRemoved(position);
}
}
private void itemAdd() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
CItem item = items.get(position);
item.setObjectNumber(item.getObjectNumber() + 1);
adapter.notifyItemChanged(position);
}
}
private void itemSubtract() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
CItem item = items.get(position);
if (item.getObjectNumber() > 0) {
item.setObjectNumber(item.getObjectNumber() - 1);
adapter.notifyItemChanged(position);
}
}
}
然后您的onBindViewHolder()
非常简单:
@Override
public void onBindViewHolder(@NonNull ViewHolderItems holder, int position)
{
holder.asignarDatos(items.get(position));
}
那么,让我们谈谈我在这里做什么
首先,我将所有侦听器设置推送到ViewHolder的构造函数中。这意味着所有侦听器只分配一次。在一个视图持有者被回收并附加到不同项目的世界中,为了使该功能仍然有效,我们必须使用getAdapterPosition()
确保始终与列表中的正确项目交互
我们必须检查NO_POSITION
,因为RecyclerView布局操作是异步的:当您从列表中删除一个项目时,存在一个间隙,该项目不再存在于适配器中,但仍显示在屏幕上。在这个间隙中,用户可能会点击一个按钮!在这些情况下,我们只是忽略用户输入
我还更改了更新项目值的方式以及显示这些更新的方式。我总是使用适配器,而不是获取文本并对其进行解析然后重新设置。请记住,RecyclerView实现的目标是能够正确显示列表中的任何元素。最好的方法是更新数据集中的元素,然后通知RecyclerView该元素已更改,然后让
注意所需的更新。您的解决方案比implements View.OnClickListener
更好,因为您为每个项分配了一个实现View.OnClickListner
接口的注释性类实例。更糟糕的是,侦听器是在onBindViewHolder
中设置的,这将被调用好几次。每次用户滚动时,都会为每个可见项调用onBindViewHolder
,然后调用一些。因此,这个示例不仅为固定数量的可见项创建匿名对象,而且每次onBindViewHolder
都是这样called@sonnet既然你这么说,那听起来太可怕了。我将进一步研究,看看如何使用“implements”。将“setOnClickListener”放在“onCreateViewHolder”方法中会改变什么吗?至少它不会被多次调用,或者我错了吗?现在它可能正在泄漏调用此CreateAdapter()
的位置的上下文。因为匿名类包含对其父类的引用(请参见)EDIT:@MikeM.-这就是@MikeM.-上一个类没有泄漏上下文的原因。请注意,您不应该将final
关键字添加到onBindViewHolder()
中的position
参数中。增量更新(例如,notifyItemInserted()
)不会重新绑定其他仅移动过的视图,因此您会有一个过时的位置值,这可能会导致错误。
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);
}
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);
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
deleteItem();
return true;
}
});
counterAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
itemAdd();
}
});
counterSubtract.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
itemSubtract();
}
});
}
private void deleteItem() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
items.remove(position);
adapter.notifyItemRemoved(position);
}
}
private void itemAdd() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
CItem item = items.get(position);
item.setObjectNumber(item.getObjectNumber() + 1);
adapter.notifyItemChanged(position);
}
}
private void itemSubtract() {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
CItem item = items.get(position);
if (item.getObjectNumber() > 0) {
item.setObjectNumber(item.getObjectNumber() - 1);
adapter.notifyItemChanged(position);
}
}
}
@Override
public void onBindViewHolder(@NonNull ViewHolderItems holder, int position)
{
holder.asignarDatos(items.get(position));
}