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


111

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

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

我在AlertDialog正按钮中使用了此功能来更新项目:

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?

Answers:


98

您可以使用notifyItemChanged(int position)RecyclerView.Adapter类中的方法。从文档中:

通知任何注册的观察员该位置的物品已更改。等效于调用notifyItemChanged(position,null);。

这是项目变更事件,而不是结构变更事件。它表明该位置数据的任何反映都已过时,应进行更新。位置上的项目保留相同的标识。

由于您已经拥有该职位,因此它应该为您工作。


9
我已经用过了,但是如果我想更新位置0,就更新位置
0、9、19

抱歉,不明白您的评论。更新哪个位置?0、9还是0到9之间的范围?
Edson Menegatti

不,这不是范围,每次更新项目时,它也会刷新不需要的项目
Elgendy 2015年

@Learner当您在位置0更新ViewHolder时,它将保持更新。RecyclerView将回收该ViewHolder并将其用于位置9,因此您可以在那里看到这些更改。我建议改为在onBindViewHolder()中设置此文本-这样,每当回收ViewHolder时,您都可以检查其位置并设置文本或使图像可见或正确显示。
Cliabhach '16

@Cliabhach在进行更改时仍然遇到相同的问题onBindViewHolder()
Choletski

39

更新单个项目

  1. 更新数据项
  2. 通知适配器更改 notifyItemChanged(updateIndex)

更改“绵羊”项,使其显示为“我喜欢绵羊”。

更新单个项目

String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);

我的完整答案和更多示例在这里


如果我想将更新的数据切换到顶部该怎么做
Choy

@Choy,更新数据后,可以将其移至索引0。请参阅此项目
Suragch

11

将更改的文本添加到模型数据列表

mdata.get(position).setSuborderStatusId("5");
mdata.get(position).setSuborderStatus("cancelled");
notifyItemChanged(position);

10

我想我对如何处理这个想法。更新与在确切位置删除和替换相同。因此,我首先使用以下代码从该位置删除该项目:

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());
}

我正在尝试实现这一点。我会在完成时给您反馈!


2
您正在执行另一步骤。只需替换position处的元素并调用item notifyItemChanged(position);即可。
toshkinl

@toshkinl您如何知道何时数据来自JSONObject?没有位置?
olajide

7

我必须先捕获需要修改的项目的位置,然后在适配器调用中解决此问题

public void refreshBlockOverlay(int position) {
    notifyItemChanged(position);
}

,这将在此特定位置为此特定项目调用onBindViewHolder(ViewHolderholder,int position)。


2

下面的解决方案为我工作:

在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
            }
        });
    }

1

对我个人而言,一种方法是使用recyclerview的适配器方法来处理其项目中的更改。

它将以类似的方式进行,在自定义回收者视图中创建一个方法,如下所示:

public void modifyItem(final int position, final Model model) {
    mainModel.set(position, model);
    notifyItemChanged(position);
}

0

在适配器类的onBindViewHolder方法中,将ViewHolder设置为setIsRecyclable(false),如下面的代码所示。

@Override
public void onBindViewHolder(RecyclerViewAdapter.ViewHolder p1, int p2)
{
    // TODO: Implement this method
    p1.setIsRecyclable(false);

    // Then your other codes
}

0

您只需要在保存单击时在警报对话框中添加以下代码

          recyclerData.add(position, updateText.getText().toString());
          recyclerAdapter.notifyItemChanged(position);

0

问题是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
}
  • 元素类型(此处为class Friend)应该实现,hashCode()并且equals()因为它是哈希图中的键。

当元素改变时,

  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);
  }
}

地图instance(Map<Friend, Integer> posMap)不一定是必需的。如果未使用map,则遍历整个列表可以找到元素的位置。


-1

那也是我的最后一个问题。在这里,我的解决方案为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);

-1

如果要创建一个对象并将其添加到适配器中使用的列表中,则在适配器中更改列表中的一个元素时,所有其他项也将更改,换句话说,其所有有关引用的内容都不会更改保存该单个对象的单独副本。


-5

在您的RecyclerView适配器中,您应该有一个ArrayList,还有一种addItemsToList(items)将列表项添加到ArrayList的方法。然后,您可以通过调用adapter.addItemsToList(items)动态添加列表项。将所有列表项添加到ArrayList之后,您可以调用adapter.notifyDataSetChanged()以显示列表。

您可以notifyDataSetChanged在适配器中使用RecyclerView


是的,我有ArrayList来存储数据,它没有任何问题,我的问题是更新此列表中的特定-existing-item
Elgendy 2015年

您应该具有要更新的项目的位置,然后只需将新项目放在其相应的位置,例如mList.add(position).setName(“ new name”); 然后使用mAdapter.notifyDataSetChanged();
Nooruddin Lakhani 2015年

4
这个答案忽略了更新单个项目的愿望。仅在整个数据集更改时才应调用notifyDataSetChanged()。
Mark McClelland 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.