Cách cập nhật / làm mới mục cụ thể trong RecyclerView


111

Tôi đang cố gắng làm mới mục cụ thể trong RecyclerView.

Câu chuyện: Bất cứ khi nào người dùng nhấp vào mục, nó sẽ hiển thị AlertDialog. Người dùng có thể nhập một số văn bản bằng cách nhấp vào nút ok. Tôi muốn hiển thị văn bản này trong mục này và hiển thị ẩn ImageView- được khai báo trong XML và bộ điều hợp ViewHolder-

Tôi đã sử dụng chức năng này trong AlertDialogNút tích cực để cập nhật mục:

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

Nhưng mã này không chỉ thay đổi itemView ở vị trí đã qua mà còn thay đổi một số itemView khác!

Làm cách nào để thay đổi chế độ xem item cụ thể một cách chính xác bằng cách nhấp vào nó?

Câu trả lời:


98

Bạn có thể sử dụng notifyItemChanged(int position)phương thức từ lớp RecyclerView.Adapter. Từ tài liệu:

Thông báo cho bất kỳ quan sát viên đã đăng ký rằng mục ở vị trí đã thay đổi. Tương đương với việc gọi InformItemChanged (position, null) ;.

Đây là sự kiện thay đổi vật phẩm, không phải sự kiện thay đổi cấu trúc. Nó chỉ ra rằng bất kỳ phản ánh nào của dữ liệu tại vị trí đều đã lỗi thời và cần được cập nhật. Mục tại vị trí vẫn giữ nguyên bản sắc.

Khi bạn đã có vị trí, nó sẽ phù hợp với bạn.


9
Tôi đã sử dụng nó rồi nhưng nếu tôi muốn cập nhật vị trí 0, nó đang cập nhật vị trí 0, 9, 19, ...
Elgendy

Xin lỗi, không hiểu nhận xét của bạn. Nó đang cập nhật vị trí nào? 0, 9 hoặc phạm vi từ 0 đến 9?
Edson Menegatti

Không, nó không phải là dao động, mỗi khi tôi đang cập nhật sản phẩm, nó làm mới mục không mong muốn cũng
Elgendy

@Learner Khi bạn cập nhật ViewHolder ở vị trí 0, nó vẫn được cập nhật. RecyclerView sẽ tái chế ViewHolder đó và sử dụng nó cho vị trí 9, vì vậy bạn sẽ thấy những thay đổi đó ở đó. Thay vào đó, tôi khuyên bạn nên đặt văn bản này trong onBindViewHolder () - theo cách đó, bất cứ khi nào ViewHolder được tái chế, bạn có thể kiểm tra vị trí của nó và đặt văn bản hoặc hiển thị hình ảnh hoặc bất cứ điều gì chính xác.
Cliabhach

@Cliabhach vấn đề vẫn còn cùng làm thay đổionBindViewHolder()
Choletski

39

Cập nhật một mặt hàng

  1. Cập nhật mục dữ liệu
  2. Thông báo cho bộ điều hợp về sự thay đổi bằng notifyItemChanged(updateIndex)

Thí dụ

Thay đổi mục "Sheep" để nó nói "Tôi thích cừu".

Cập nhật một mặt hàng

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

Câu trả lời đầy đủ của tôi với nhiều ví dụ hơn là ở đây .


làm thế nào để cho rằng nếu tôi muốn các dữ liệu được cập nhật chuyển sang đầu
Choy

@Choy, sau khi bạn cập nhật dữ liệu, bạn có thể di chuyển nó đến chỉ số 0. Xem Move đơn hàng phần của mặt hàng này
Suragch

11

Thêm văn bản đã thay đổi vào danh sách dữ liệu mô hình của bạn

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

10

Tôi nghĩ tôi có một ý tưởng về cách giải quyết vấn đề này. Việc cập nhật cũng giống như xóa và thay thế tại vị trí chính xác. Vì vậy, trước tiên tôi xóa mục khỏi vị trí đó bằng cách sử dụng mã bên dưới:

public void removeItem(int position){
    mData.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, mData.size());
}

và sau đó tôi sẽ thêm mục tại vị trí cụ thể đó như hình dưới đây:

public void addItem(int position, Landscape landscape){
    mData.add(position, landscape);
    notifyItemInserted(position);
    notifyItemRangeChanged(position, mData.size());
}

Tôi đang cố gắng thực hiện điều này ngay bây giờ. Tôi sẽ cung cấp cho bạn một phản hồi khi tôi hoàn thành!


2
Bạn đang thực hiện thêm một bước. Chỉ cần thay thế phần tử tại vị trí và gọi mục messageItemChanged (vị trí);
toshkinl

@toshkinl Làm thế nào bạn biết khi nào dữ liệu đến từ JSONObject? không có chức vụ?
olajide

7

Tôi phải giải quyết vấn đề này bằng cách bắt vị trí của mục cần sửa đổi và sau đó trong lệnh gọi bộ điều hợp

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

, điều này sẽ gọi onBindViewHolder (ViewHolder Holder, int position) cho mục cụ thể này tại vị trí cụ thể này.


2

Giải pháp dưới đây phù hợp với tôi:

Trên một mục RecyclerView, người dùng sẽ nhấp vào một nút nhưng một chế độ xem khác như TextView sẽ cập nhật mà không cần thông báo trực tiếp cho bộ điều hợp:

Tôi đã tìm thấy một giải pháp tốt cho việc này mà không sử dụng phương thứctifyDataSetChanged (), phương thức này tải lại tất cả dữ liệu của RecyclerView, vì vậy nếu bạn có hình ảnh hoặc video bên trong mục thì chúng sẽ tải lại và trải nghiệm người dùng sẽ không tốt:

Đây là ví dụ về việc nhấp vào biểu tượng thích ImageView và chỉ cập nhật một TextView duy nhất (Có thể cập nhật thêm lượt xem theo cùng một cách của cùng một mục) để hiển thị cập nhật số lượt thích sau khi thêm +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

Một cách đã hiệu quả với cá nhân tôi, đó là sử dụng các phương pháp bộ điều hợp của tái chế để đối phó với những thay đổi trong các mặt hàng của nó.

Nó sẽ diễn ra theo cách tương tự như thế này, hãy tạo một phương pháp trong chế độ xem của người tái chế tùy chỉnh của bạn như sau:

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

0

Trong lớp bộ điều hợp của bạn, trong phương thức onBindViewHolder, hãy đặt ViewHolder thành setIsRecyclable (false) như trong mã bên dưới.

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

    // Then your other codes
}

0

bạn chỉ cần thêm mã sau vào hộp thoại cảnh báo khi bấm lưu

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

0

Vấn đề là RecyclerView.Adatperkhông cung cấp bất kỳ phương thức nào trả về chỉ mục của phần tử

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

Cách giải quyết của tôi là tạo một phiên bản bản đồ cho (phần tử, vị trí)

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
}
  • kiểu phần tử (ở đây là lớp Friend) nên triển khai hashCode()equals()vì nó là chìa khóa trong bản đồ băm.

khi một phần tử thay đổi,

  void someMethod() {
    Friend friend = ...;
    friend.setPhoneNumber('xxxxx');

    int position = friendAdapter.indexOf(friend);
    friendAdapter.notifyItemChanged(position);

  }

Nên xác định một phương thức trợ giúp

public class FriendAdapter extends extends RecyclerView.Adapter<MyViewHolder> {

  public void friendUpdated(Friend friend) {
    int position = this.indexOf(friend);
    this.notifyItemChanged(position);
  }
}

Bản đồ instance ( Map<Friend, Integer> posMap) không nhất thiết phải có. Nếu bản đồ không được sử dụng, lặp lại trong suốt danh sách có thể tìm thấy vị trí của một phần tử.


-1

Đó cũng là vấn đề cuối cùng của tôi. Đây là giải pháp của tôi, tôi sử dụng Mô hình dữ liệu và bộ điều hợp cho RecyclerView của mình

 /*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

nếu bạn đang tạo một đối tượng và thêm nó vào danh sách mà bạn sử dụng trong bộ điều hợp, khi bạn thay đổi một phần tử của danh sách trong bộ điều hợp, tất cả các mục khác của bạn cũng thay đổi, nói cách khác là tất cả về tham chiếu còn danh sách của bạn thì không giữ các bản sao riêng biệt của đối tượng duy nhất đó.


-5

Trong bộ điều hợp RecyclerView của bạn, bạn nên có một ArrayList và một phương pháp addItemsToList(items)để thêm các mục danh sách vào ArrayList. Sau đó, bạn có thể thêm các mục danh sách bằng cách gọi adapter.addItemsToList(items)động. Sau khi tất cả các mục danh sách của bạn được thêm vào ArrayList thì bạn có thể gọiadapter.notifyDataSetChanged() để hiển thị danh sách của mình.

Bạn có thể sử dụng notifyDataSetChangedbộ điều hợp trong RecyclerView


vâng tôi có ArrayList để cho dữ liệu, nó hoạt động mà không cần bất kỳ vấn đề, vấn đề của tôi trong việc cập nhật mục cụ thể -existing- trong danh sách này
Elgendy

bạn nên có vị trí của mục đang cập nhật, sau đó bạn chỉ cần đặt mục mới vào vị trí tương ứng của nó như mList.add (position) .setName ("tên mới"); sau đó sử dụng mAdapter.notifyDataSetChanged ();
Nooruddin Lakhani

4
Câu trả lời này bỏ qua mong muốn cập nhật một mục duy nhất. Chỉ nên thực hiện việc gọi InformDataSetChanged () khi toàn bộ tập dữ liệu thay đổi.
Mark McClelland
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.