วิธีอัปเดต / รีเฟรชรายการเฉพาะใน 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 เฉพาะอย่างถูกต้องได้อย่างไรโดยคลิกที่มัน

คำตอบ:


98

คุณสามารถใช้notifyItemChanged(int position)วิธีการจากคลาส RecyclerView.Adapter จากเอกสารประกอบ:

แจ้งให้ผู้สังเกตการณ์ที่ลงทะเบียนทราบว่ารายการในตำแหน่งมีการเปลี่ยนแปลง เทียบเท่ากับการโทร alertItemChanged (ตำแหน่ง null);.

นี่คือเหตุการณ์การเปลี่ยนแปลงรายการไม่ใช่เหตุการณ์การเปลี่ยนแปลงโครงสร้าง บ่งชี้ว่าการสะท้อนข้อมูลใด ๆ ในตำแหน่งล้าสมัยและควรได้รับการอัปเดต รายการที่ตำแหน่งยังคงรักษาเอกลักษณ์เดิม

ในฐานะที่คุณมีตำแหน่งอยู่แล้วก็ควรจะเหมาะกับคุณ


9
ฉันใช้ไปแล้ว แต่ถ้าฉันต้องการอัปเดตตำแหน่ง 0 กำลังอัปเดตตำแหน่ง 0, 9, 19, ...
Elgendy

ขออภัยไม่เข้าใจความคิดเห็นของคุณ กำลังอัปเดตตำแหน่งใด 0, 9 หรือช่วงระหว่าง 0 ถึง 9?
Edson Menegatti

ไม่มันไม่ใช่ช่วงทุกครั้งที่ฉันอัปเดตรายการจะรีเฟรชรายการที่ไม่ต้องการเช่นกัน
Elgendy

@Learner เมื่อคุณอัปเดต ViewHolder ที่ตำแหน่ง 0 จะมีการอัปเดตอยู่เสมอ RecyclerView จะรีไซเคิล ViewHolder นั้นและใช้สำหรับตำแหน่ง 9 ดังนั้นคุณจะเห็นการเปลี่ยนแปลงเหล่านั้นที่นั่น ฉันขอแนะนำให้ตั้งค่าข้อความนี้ใน onBindViewHolder () แทน - ด้วยวิธีนี้เมื่อใดก็ตามที่ ViewHolder ถูกรีไซเคิลคุณสามารถตรวจสอบตำแหน่งและตั้งค่าข้อความหรือทำให้มองเห็นภาพหรืออะไรก็ได้อย่างถูกต้อง
Cliabhach

@Cliabhach ยังคงมีปัญหาเดิมในการเปลี่ยนแปลงในonBindViewHolder()
Choletski

39

อัปเดตรายการเดียว

  1. อัปเดตรายการข้อมูล
  2. แจ้งอะแดปเตอร์ของการเปลี่ยนแปลงด้วย notifyItemChanged(updateIndex)

ตัวอย่าง

เปลี่ยนรายการ "Sheep" ให้มีข้อความ "ฉันชอบแกะ"

อัปเดตรายการเดียว

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

คำตอบของฉันเต็มไปด้วยตัวอย่างมากขึ้นที่นี่


จะทำอย่างไรถ้าฉันต้องการให้ข้อมูลที่อัปเดตเปลี่ยนไปด้านบน
Choy

@Choy หลังจากอัปเดตข้อมูลแล้วคุณสามารถย้ายไปที่ดัชนี 0 ได้ดูส่วน Move Single Item ของรายการนี้
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
คุณกำลังทำอีกหนึ่งขั้นตอน เพียงแค่แทนที่องค์ประกอบที่ตำแหน่งและเรียกรายการแจ้งเตือน (ตำแหน่ง);
toshkinl

@toshkinl คุณจะรู้ได้อย่างไรว่าข้อมูลมาจาก JSONObject ไม่มีตำแหน่ง?
olajide

7

ฉันต้องแก้ปัญหานี้ด้วยการจับตำแหน่งของรายการที่ต้องแก้ไขจากนั้นในการเรียกอะแดปเตอร์

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

สิ่งนี้จะเรียก onBindViewHolder (ผู้ถือ ViewHolder ตำแหน่ง int) สำหรับรายการเฉพาะนี้ที่ตำแหน่งเฉพาะนี้


2

โซลูชันด้านล่างใช้ได้ผลสำหรับฉัน:

ในรายการ RecyclerView ผู้ใช้จะคลิกปุ่ม แต่มุมมองอื่นเช่น TextView จะอัปเดตโดยไม่ต้องแจ้งอะแดปเตอร์โดยตรง:

ฉันพบวิธีแก้ปัญหาที่ดีสำหรับสิ่งนี้โดยไม่ต้องใช้เมธอด informDataSetChanged () วิธีนี้จะโหลดข้อมูลทั้งหมดของรีไซเลอร์วิวซ้ำดังนั้นหากคุณมีรูปภาพหรือวิดีโออยู่ในรายการพวกเขาจะโหลดซ้ำและประสบการณ์ของผู้ใช้จะไม่ดี:

นี่คือตัวอย่างของการคลิกที่ไอคอน 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);
}

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

วิธีแก้ปัญหาของฉันคือสร้างอินสแตนซ์แผนที่สำหรับ (องค์ประกอบตำแหน่ง) 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ไม่จำเป็นต้องใช้อินสแตนซ์แผนที่ ( ) หากไม่ได้ใช้แผนที่การวนซ้ำตลอดรายการสามารถค้นหาตำแหน่งขององค์ประกอบได้


-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 สำหรับข้อมูลมันใช้งานได้โดยไม่มีปัญหาใด ๆ ปัญหาของฉันในการอัปเดต
Elgendy

คุณควรมีตำแหน่งของรายการที่กำลังอัปเดตจากนั้นคุณก็ต้องใส่รายการใหม่ในตำแหน่งที่เกี่ยวข้องเช่น mList.add (ตำแหน่ง) .setName ("ชื่อใหม่"); จากนั้นใช้ mAdapter.notifyDataSetChanged ();
Nooruddin Lakhani

4
คำตอบนี้ไม่สนใจความปรารถนาที่จะอัปเดตรายการเดียว การโทร alertDataSetChanged () ควรทำก็ต่อเมื่อชุดข้อมูลทั้งหมดเปลี่ยนไป
Mark McClelland
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.