Как обновить / обновить конкретный элемент в RecyclerView

112

Я пытаюсь обновить конкретный элемент в 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, щелкнув по нему?

Elgendy
источник

Ответы:

98

Вы можете использовать notifyItemChanged(int position)метод из класса RecyclerView.Adapter. Из документации:

Сообщите всем зарегистрированным наблюдателям, что позиция в позиции изменилась. Эквивалентно вызову notifyItemChanged (position, null) ;.

Это событие изменения элемента, а не событие структурного изменения. Это означает, что любое отражение данных в позиции устарело и должно быть обновлено. Элемент в позиции сохраняет ту же идентичность.

Поскольку у вас уже есть позиция, она должна работать на вас.

Эдсон Менегатти
источник
9
Я уже использовал его, но если я хочу обновить позицию 0, он обновляет позицию 0, 9, 19, ...
Эльгенды
Извините, не поняла ваш комментарий. Какая позиция обновляется? 0, 9 или диапазон от 0 до 9?
Эдсон Менегатти
Нет, это не диапазон, каждый раз, когда я обновляю элемент, он также обновляет ненужные элементы
Эльгенды
@Learner Когда вы обновляете ViewHolder в позиции 0, он остается обновленным. RecyclerView перерабатывает этот ViewHolder и использует его для позиции 9, поэтому вы видите эти изменения там. Я рекомендую вместо этого установить этот текст в onBindViewHolder () - таким образом, всякий раз, когда ViewHolder перерабатывается, вы можете проверить его положение и установить текст или сделать изображение видимым или что-то еще правильно.
Cliabhach
@Cliabhach все еще та же проблема с внесением измененийonBindViewHolder()
Холецкий
39

Обновить отдельный элемент

  1. Обновите элемент данных
  2. Сообщите адаптеру об изменении с помощью notifyItemChanged(updateIndex)

пример

Измените пункт «Овцы» так, чтобы в нем говорилось «Я люблю овец».

Обновить отдельный элемент

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

Мой полный ответ с другими примерами здесь .

Suragch
источник
как это сделать, если я хочу, чтобы обновленные данные переключились наверх
Чой
@Choy, после обновления данных вы можете переместить их в индекс 0. См. Раздел «Перемещение одного элемента» этого элемента
Сурагч,
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());
}

Я пытаюсь реализовать это сейчас. Я дам вам отзыв, когда закончу!

ЭГБЕНЧОНГ II Дж. Аюк
источник
2
Вы делаете один дополнительный шаг. Просто замените элемент в позиции и вызовите элемент notifyItemChanged (position);
toshkinl
@toshkinl Как узнать, что данные поступают из JSONObject? без позиции?
olajide
7

Мне нужно решить эту проблему, поймав позицию элемента, который необходимо изменить, а затем в вызове адаптера

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

, это вызовет onBindViewHolder (держатель ViewHolder, позиция int) для этого конкретного элемента в этой конкретной позиции.

haneenCo
источник
2

Ниже решение сработало для меня:

В элементе RecyclerView пользователь нажмет кнопку, но другое представление, такое как TextView, будет обновляться без прямого уведомления адаптера:

Я нашел хорошее решение для этого без использования метода notifyDataSetChanged (), этот метод перезагружает все данные recyclerView, поэтому, если у вас есть изображение или видео внутри элемента, они будут перезагружены, и пользовательский интерфейс не будет хорошим:

Вот пример того, как щелкнуть значок ImageView like и обновить только один 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);
}
user3709410
источник
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
}
shankar_vl
источник
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);
}

Мой обходной путь - создать экземпляр карты для (element, position) s

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()потому что он является ключевым в хэш-карте.

когда элемент изменился,

  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) не обязательно требуется. Если карта не используется, цикл по списку может найти позицию элемента.

chmin
источник
-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

если вы создаете один объект и добавляете его в список, который используете в своем адаптере, когда вы меняете один элемент своего списка в адаптере, все другие элементы тоже меняются, другими словами, все дело в ссылках, а ваш список не держать отдельные копии этого единственного объекта.

A.sobhdel
источник
-5

В вашем адаптере RecyclerView у вас должен быть ArrayList, а также один метод addItemsToList(items)для добавления элементов списка в ArrayList. Затем вы можете adapter.addItemsToList(items)динамически добавлять элементы списка по вызову . После того, как все элементы вашего списка добавлены в ArrayList, вы можете вызватьadapter.notifyDataSetChanged() чтобы отобразить свой список.

Вы можете использовать notifyDataSetChangedв адаптере для RecyclerView

Нооруддин Лахани
источник
да, у меня есть ArrayList для данных, он работает без проблем, моя проблема с обновлением определенного-существующего- элемента в этом списке
Эльгенды
у вас должна быть позиция элемента, которая обновляется, тогда вам просто нужно поместить новый элемент в соответствующую позицию, например mList.add (position) .setName ("новое имя"); затем используйте mAdapter.notifyDataSetChanged ();
Норуддин Лакхани 08
4
Этот ответ игнорирует желание обновить один элемент. Вызов notifyDataSetChanged () должен выполняться только при изменении всего набора данных.
Марк МакКлелланд,