如何更新/刷新 RecyclerView 中的特定项目
Posted
技术标签:
【中文标题】如何更新/刷新 RecyclerView 中的特定项目【英文标题】:How to update/refresh specific item in RecyclerView 【发布时间】:2015-12-04 02:46:18 【问题描述】:我正在尝试刷新 RecyclerView
中的特定项目。
故事:当用户点击项目时,它会显示AlertDialog
。用户可以通过单击确定按钮键入一些文本。我想在此项目中显示此文本并显示不可见的 ImageView
- 在 XML 和适配器中声明 ViewHolder
-
我在AlertDialog
Positive Button中使用了这个功能来更新item:
private void updateListItem(int position)
View view = layoutManager.findViewByPosition(position);
ImageView medicineSelected = (ImageView) view.findViewById(R.id.medicine_selected);
medicineSelected.setVisibility(View.VISIBLE);
TextView orderQuantity = (TextView) view.findViewById(R.id.order_quantity);
orderQuantity.setVisibility(View.VISIBLE);
orderQuantity.setText(quantity + " packet added!");
medicinesArrayAdapter.notifyItemChanged(position);
但是这段代码不仅改变了传递位置的itemView,还改变了其他一些itemView!
我应该如何通过点击正确更改特定的itemView?
【问题讨论】:
【参考方案1】:您可以使用 RecyclerView.Adapter 类中的notifyItemChanged(int position)
方法。来自文档:
通知任何已注册的观察者该位置的项目已更改。 相当于调用 notifyItemChanged(position, null);。
这是一个项目更改事件,而不是结构更改事件。它 表示位置数据的任何反映都已过时 并且应该更新。位置的项目保持相同的身份。
既然你已经有了这个职位,它应该适合你。
【讨论】:
我已经用过了,但是如果我想更新位置 0,它正在更新位置 0, 9, 19, ... 抱歉,没看懂您的评论。它更新了哪个位置? 0、9 还是 0 到 9 之间的范围? 不,不是范围,每次我更新项目时,它都会刷新不需要的项目 @Learner 当您更新位置 0 的 ViewHolder 时,它会保持更新。 RecyclerView 将 recycle 该 ViewHolder 并将其用于位置 9,因此您会在那里看到这些更改。我建议在 onBindViewHolder() 中设置此文本 - 这样,每当 ViewHolder 被回收时,您都可以检查其位置并设置文本或使图像可见或正确。 @Cliabhach 在onBindViewHolder()
中进行更改时仍然存在同样的问题【参考方案2】:
更新单项
-
更新数据项
使用
notifyItemChanged(updateIndex)
通知适配器更改
示例
更改“绵羊”项目,使其显示“我喜欢绵羊”。
String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);
我的完整答案是here。
【讨论】:
如果我想更新的数据切换到顶部怎么办 @Choy,更新数据后,您可以将其移动到索引 0。请参阅 this item 的移动单个项目部分 @Suragch 我可以知道它调用哪个回调来更新适配器中的项目。它当然不会调用 onBindViewHolder 方法,我记录了它。 @SouravKannanthaB,对不起,我不确定。我切换到 Flutter,所以我忘记了很多关于 android 的东西。 (顺便说一下,ListViews 在 Flutter 中更容易处理。我很高兴不再使用 RecyclerViews。)【参考方案3】:将更改后的文本添加到模型数据列表中
mdata.get(position).setSuborderStatusId("5");
mdata.get(position).setSuborderStatus("cancelled");
notifyItemChanged(position);
【讨论】:
看这里如何获得位置***.com/questions/53706830/…【参考方案4】:我想我对如何处理这个问题有一个想法。更新与在确切位置删除和替换相同。所以我首先使用下面的代码从该位置删除项目:
public void removeItem(int position)
mData.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mData.size());
然后我会在该特定位置添加项目,如下所示:
public void addItem(int position, Landscape landscape)
mData.add(position, landscape);
notifyItemInserted(position);
notifyItemRangeChanged(position, mData.size());
我现在正在尝试实现这一点。完成后我会给你一个反馈!
【讨论】:
你正在做一个额外的步骤。只需替换 position 处的元素并调用 item notifyItemChanged(position); @toshkinl 您如何知道数据何时来自 JSONObject?没有职位?【参考方案5】:我必须通过捕获需要修改的项目的位置来解决这个问题 然后在适配器调用中
public void refreshBlockOverlay(int position)
notifyItemChanged(position);
,这将在此特定位置为该特定项目调用 onBindViewHolder(ViewHolder holder, int position)。
【讨论】:
【参考方案6】:对我个人有用的一种方法是使用 recyclerview 的适配器方法来处理其项目的更改。
它会以类似的方式进行,在您的自定义回收器视图中创建一个方法,有点像这样:
public void modifyItem(final int position, final Model model)
mainModel.set(position, model);
notifyItemChanged(position);
【讨论】:
这是正确的答案,但你应该解释一下如何改变视图。 如何根据唯一的用户 ID 从回收站视图中获取位置【参考方案7】:以下解决方案对我有用:
在 RecyclerView 项目上,用户将单击一个按钮,但另一个视图(如 TextView)将更新,而无需直接通知适配器:
我在不使用 notifyDataSetChanged() 方法的情况下找到了一个很好的解决方案,该方法会重新加载 recyclerView 的所有数据,因此如果您在项目内有图像或视频,那么它们将重新加载并且用户体验会不好:
这是一个示例,点击类似 ImageView 的图标,仅更新单个 TextView(可能以相同的方式更新更多视图)以在添加 +1 后显示类似计数更新:
// View holder class inside adapter class
public class MyViewHolder extends RecyclerView.ViewHolder
ImageView imageViewLike;
public MyViewHolder(View itemView)
super(itemView);
imageViewLike = itemView.findViewById(R.id.imageViewLike);
imageViewLike.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
int pos = getAdapterPosition(); // Get clicked item position
TextView tv = v.getRootView().findViewById(R.id.textViewLikeCount); // Find textView of recyclerView item
resultList.get(pos).setLike(resultList.get(pos).getLike() + 1); // Need to change data list to show updated data again after scrolling
tv.setText(String.valueOf(resultList.get(pos).getLike())); // Set data to TextView from updated list
);
【讨论】:
【参考方案8】:我试过了,它对我有用:
private void updateItem(Object item, int position, int itemValue)
item.setItemNumber(itemValue) // update item field
notifyItemChanged(position, item);
确保传入要更新或刷新的项目的对象、它在列表中的位置和值。
【讨论】:
【参考方案9】:问题是RecyclerView.Adatper
没有提供任何返回元素索引的方法
public abstract static class Adapter<VH extends ViewHolder>
/**
* returns index of the given element in adapter, return -1 if not exist
*/
public int indexOf(Object elem);
我的解决方法是为(元素,位置)创建一个地图实例
public class FriendAdapter extends RecyclerView.Adapter<MyViewHolder>
private Map<Friend, Integer> posMap ;
private List<Friend> friends;
public FriendAdapter(List<Friend> friends )
this.friends = new ArrayList<>(friends);
this.posMap = new HashMap<>();
for(int i = 0; i < this.friends.size(); i++)
posMap.put(this.friends.get(i), i);
public int indexOf(Friend friend)
Integer position = this.posMap.get(elem);
return position == null ? -1 : position;
// skip other methods in class Adapter
元素类型(此处为类Friend
)应实现hashCode()
和equals()
,因为它是hashmap 中的关键。
当元素改变时,
void someMethod()
Friend friend = ...;
friend.setPhoneNumber('xxxxx');
int position = friendAdapter.indexOf(friend);
friendAdapter.notifyItemChanged(position);
最好定义一个辅助方法
public class FriendAdapter extends extends RecyclerView.Adapter<MyViewHolder>
public void friendUpdated(Friend friend)
int position = this.indexOf(friend);
this.notifyItemChanged(position);
不一定需要地图实例(Map<Friend, Integer> posMap
)。
如果不使用map,遍历list可以找到元素的位置。
【讨论】:
【参考方案10】:notifYItemsChanged 将通知某些项目已更改,因此无论哪个项目已更改,都会更新所有列表。相反,您应该使用 DiffUtil。
在此处了解它们:https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil
【讨论】:
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 link-only-answers【参考方案11】:这也是我的最后一个问题。这是我的解决方案 我为我的 RecyclerView 使用数据模型和适配器
/*Firstly, register your new data to your model*/
DataModel detail = new DataModel(id, name, sat, image);
/*after that, use set to replace old value with the new one*/
int index = 4;
mData.set(index, detail);
/*finally, refresh your adapter*/
if(adapter!=null)
adapter.notifyItemChanged(index);
【讨论】:
【参考方案12】:您只需要在保存点击时在警报对话框中添加以下代码
recyclerData.add(position, updateText.getText().toString());
recyclerAdapter.notifyItemChanged(position);
【讨论】:
【参考方案13】:如果您正在创建一个对象并将其添加到您在适配器中使用的列表中, 当您更改适配器中列表的一个元素时,所有其他项目也会更改 换句话说,它的全部内容都与引用有关,并且您的列表不包含该单个对象的单独副本。
【讨论】:
以上是关于如何更新/刷新 RecyclerView 中的特定项目的主要内容,如果未能解决你的问题,请参考以下文章
如何更新 RecyclerView 中某个项目的特定 TextView?
如何彻底更改 recyclerview 中的 item 布局中的某个控件的某个属性