如何更新/刷新 RecyclerView 中的特定项目

Posted

技术标签:

【中文标题】如何更新/刷新 RecyclerView 中的特定项目【英文标题】:How to update/refresh specific item in RecyclerView 【发布时间】:2015-12-04 02:46:18 【问题描述】:

我正在尝试刷新 RecyclerView 中的特定项目。

故事:当用户点击项目时,它会显示AlertDialog。用户可以通过单击确定按钮键入一些文本。我想在此项目中显示此文本并显示不可见的 ImageView - 在 XML 和适配器中声明 ViewHolder -

我在AlertDialogPositive 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&lt;Friend, Integer&gt; 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 布局中的某个控件的某个属性

RecyclerView局部刷新

当另一个片段中的数据发生更改时,如何刷新一个片段中的 RecyclerView

RecyclerView 刷新踩坑记

RecyclerView底部刷新实现具体解释