RecyclerView에서 특정 항목을 업데이트 / 새로 고침하는 방법


112

에서 특정 항목을 새로 고치려고합니다 RecyclerView.

스토리 : 사용자가 항목을 클릭 할 때마다 AlertDialog. 사용자는 확인 버튼을 클릭하여 텍스트를 입력 할 수 있습니다. 나는이 항목에서이 텍스트를 표시하려면 보이지 않는 보여 ImageView- XML 및 어댑터를 선언 ViewHolder-

AlertDialog항목을 업데이트하기 위해 Positive Button 에서이 기능을 사용했습니다 .

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 (s)도 변경합니다!

특정 itemView를 클릭하여 올바르게 변경하려면 어떻게해야합니까?

답변:


98

notifyItemChanged(int position)RecyclerView.Adapter 클래스 의 메서드를 사용할 수 있습니다 . 문서에서 :

등록 된 관찰자에게 위치의 항목이 변경되었음을 알립니다. notifyItemChanged (position, null); 호출과 동일합니다.

이것은 구조 변경 이벤트가 아니라 항목 변경 이벤트입니다. 위치에있는 데이터의 반영이 오래되어 업데이트해야 함을 나타냅니다. 위치의 항목은 동일한 ID를 유지합니다.

당신이 이미 그 위치를 가지고 있기 때문에 그것은 당신을 위해 일할 것입니다.


9
나는 이미 그것을 사용하지만 난 업데이트 위치 0,이 업데이트되어 위치 0, 9, 19 싶다면 ...
Elgendy

죄송합니다. 귀하의 의견을 이해하지 못했습니다. 어느 위치가 업데이트되고 있습니까? 0, 9 또는 0과 9 사이의 범위?
Edson Menegatti 2015 년

아니, 그것뿐만 아니라 원치 않는 항목을 새로 고침, 내가 항목을 업데이트하고 때마다 범위가 아닙니다
Elgendy

@Learner 위치 0에서 ViewHolder를 업데이트하면 업데이트 된 상태로 유지됩니다. RecyclerView는 해당 ViewHolder 를 재활용 하고 위치 9에 사용하므로 해당 변경 사항이 표시됩니다. 대신이 텍스트를 onBindViewHolder ()에 설정하는 것이 좋습니다. 이렇게하면 ViewHolder가 재활용 될 때마다 위치를 확인하고 텍스트를 설정하거나 이미지를 표시하거나 올바르게 표시 할 수 있습니다.
Cliabhach

@Cliabhach는 여전히 변경 사항을 수행하는 동일한 문제onBindViewHolder()
Choletski

39

단일 항목 업데이트

  1. 데이터 항목 업데이트
  2. 어댑터에 변경 사항을 알리십시오. notifyItemChanged(updateIndex)

"I like sheep"이라고 표시되도록 "Sheep"항목을 변경합니다.

단일 항목 업데이트

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
한 가지 추가 단계를 수행하고 있습니다. 위치의 요소를 교체하고 항목을 호출하십시오. notifyItemChanged (position);
toshkinl

@toshkinl JSONObject에서 데이터가 언제 오는지 어떻게 알 수 있습니까? 위치가 없습니까?
olajide

7

수정해야하는 항목의 위치를 ​​파악한 다음 어댑터 호출에서이 문제를 해결해야합니다.

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

,이 특정 위치에서이 특정 항목에 대해 onBindViewHolder (ViewHolder holder, int position)를 호출합니다.


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

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
}
  • 요소 유형 (여기서는 클래스 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()목록을 표시하기 위해 호출 할 수 있습니다 .

notifyDataSetChangedRecyclerView의 어댑터에서 사용할 수 있습니다.


예, 데이터에 대한 ArrayList가 있습니다. 문제없이 작동합니다.이 목록에서 특정-기존 항목을 업데이트하는 데 문제가 있습니다.
Elgendy

업데이트중인 항목의 위치가 있어야하며 mList.add (position) .setName ( "new name");과 같은 해당 위치에 새 항목을 놓기 만하면됩니다. 그런 다음 mAdapter.notifyDataSetChanged ();
Nooruddin Lakhani 2015 년

4
이 대답은 단일 항목을 업데이트하려는 욕구를 무시합니다. notifyDataSetChanged () 호출은 전체 데이터 세트가 변경된 경우에만 수행되어야합니다.
Mark McClelland 2015
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.