사용자 정의 어댑터에서 notifyDataSetChange가 작동하지 않음


126

내을 다시 채울 때 ListViewAdapter.

문제 :

updateReceiptsList에서 호출 Adapter하면 데이터가 새로 고쳐 지지만 ListView변경 사항이 반영되지 않습니다.

질문 :

ListView전화 할 때 새 데이터가 표시 되지 않는 이유는 무엇 notifyDataSetChanged입니까?

어댑터 :

public class ReceiptListAdapter extends BaseAdapter {

    public List<Receipt> receiptlist;
    private Context context;
    private LayoutInflater inflater;
    private DateHelpers dateH;

    public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
        context = mcontext;
        receiptlist = rl;
        Collections.reverse(receiptlist);
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        dateH = new DateHelpers();
    }

    @Override
    public int getCount() {
        try {
            int size = receiptlist.size();
            return size;
        } catch(NullPointerException ex) {
            return 0;
        }
    }

    public void updateReceiptsList(List<Receipt> newlist) {
        receiptlist = newlist;
        this.notifyDataSetChanged();
    }

    @Override
    public Receipt getItem(int i) {
        return receiptlist.get(i);
    }

    @Override
    public long getItemId(int i) {
        return receiptlist.get(i).getReceiptId() ;
    }

    private String getPuntenString(Receipt r) {
        if(r.getPoints().equals("1")) {
            return "1 punt";
        }
        return r.getPoints()+" punten";
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View vi=convertView;

        final Receipt receipt = receiptlist.get(position);
        ReceiptViewHolder receiptviewholder;
        Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");        
        Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf");

        if (vi == null) { //convertview==null
            receiptviewholder = new ReceiptViewHolder();
            vi = inflater.inflate(R.layout.view_listitem_receipt, null);
            vi.setOnClickListener(null);
            vi.setOnLongClickListener(null);
            vi.setLongClickable(false);
            receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop);
            receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date);
            receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price);
            receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points);
            receiptviewholder.shop.setTypeface(tf_hn_bold);
            receiptviewholder.price.setTypeface(tf_hn_bold);
            vi.setTag(receiptviewholder);
        }else{//convertview is not null
            receiptviewholder = (ReceiptViewHolder)vi.getTag();
        }

        receiptviewholder.shop.setText(receipt.getShop());
        receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate())));
        receiptviewholder.price.setText("€ "+receipt.getPrice());
        receiptviewholder.points.setText(getPuntenString(receipt));

        vi.setClickable(false);
        return vi;
    }

    public static class ReceiptViewHolder {
        public TextView shop;
        public TextView date;
        public TextView price;
        public TextView points;
    }

    public Object getFilter() {
        // XXX Auto-generated method stub
        return null;
    }

}

--편집하다:

해결 방법을 찾았습니다.

몇 가지 기능 코드를 갖기 위해 지금 수행합니다.

listview.setAdapter( new ReceiptListAdapter(activity,mcontext, -new dataset-);

작동하지만 작동 방식은 아닙니다.


stackoverflow.com/a/4198569/2382964 , 안녕 Jasper이 링크를 참조하십시오 ... 이것은 당신을 도울 것입니다.
Tushar Pandey 2013-06-04

등등 notifyItemInserted, notifyItemRemoved, 같은 다른 방법을 시도
Reejesh PK

답변:


334

방법 변경

public void updateReceiptsList(List<Receipt> newlist) {
    receiptlist = newlist;
    this.notifyDataSetChanged();
}

public void updateReceiptsList(List<Receipt> newlist) {
    receiptlist.clear();
    receiptlist.addAll(newlist);
    this.notifyDataSetChanged();
}

따라서 어댑터의 DataSet과 동일한 개체를 유지합니다.


객체 ReceiptListObject대신에 부모 객체를 갖는 것을 고려하십시오. List그러면이 문제를 해결하기 위해 무엇을 할 수 있습니까?
prom85

@ prom85는 ArrayAdapters가 목록이나 배열 이외의 객체에도 바인딩 할 수 있습니까? 난 몰랐 거든.
tolgap

그것은 관하여 BaseAdapter내가 (같은이 개체의 사용자 지정 개체 사용 사용자 정의 기능을 가지고 그렇다면 ...이 어댑터가 바인더 제본 된 자료에 모르는 custObject.getCount()custObject.getChildAt(int i)예를 들어), 그리고이 객체를 교환 할, notifyDataSetChanged작동하지 않습니다 ... 어쨌든, 나는이 문제가 발생하지 않는다고 생각합니다ArrayAdapter
prom85

3
첫 번째 방법이 작동하지 않는 이유와 두 번째 방법이 BaseAdapter에서 작동하는 이유를 설명해 주시겠습니까?
Tooroop 2014 년

1
감사 또는 +1 같은 의견은 허용되지 않습니다 있지만, 일부 답변에 정말 등 감사 :)주고
무하마드 Saqib

24

나는 똑같은 문제가 있고 그것을 깨닫습니다. 어댑터를 생성하고이를 listview로 설정하면 listview는 어댑터가 보유한 메모리의 어딘가에있는 객체를 가리키고이 객체의 데이터는 listview에 표시됩니다.

adapter = new CustomAdapter(data);
listview.setadapter(adapter);

다른 데이터로 어댑터에 대한 객체를 다시 생성하고 notifydatasetchanged () :

adapter = new CustomAdapter(anotherdata);
adapter.notifyDataSetChanged();

목록이 다른 객체를 가리키고 있고,이 객체는 어댑터의 새 객체에 대해 전혀 알지 못하며, notifyDataSetChanged ()는 아무 영향도주지 않기 때문에 목록보기의 데이터에는 영향을주지 않습니다. 따라서 객체의 데이터를 변경하고 어댑터에 대한 새 객체를 다시 생성하지 않도록해야합니다.


10
어댑터 개체를 다시 만들고 있지만 효율적이지 않습니다
Alezis

2
@Alezis 나는 그것이 Nhan이 의미하는 바라고 생각합니다.
Neeraj Sewani

17

이 문제의 원인과 다른 답변 스레드에서 처리하는 방법을 이미 설명했듯이 여기 . 여전히 여기에 솔루션 요약을 공유하고 있습니다.

notifyDataSetChanged()작동하지 않는 주된 이유 중 하나는

어댑터가 목록에 대한 참조를 잃습니다 .

새 목록을 만들고 Adapter. 항상 다음 지침을 따르십시오.

  1. arrayList전역 적으로 선언하면서 초기화하십시오 .
  2. null 및 빈 값을 확인하지 않고 목록을 어댑터에 직접 추가합니다. 어댑터를 목록에 직접 설정하십시오 (조건을 확인하지 마십시오). 어댑터는 데이터를 변경할 때마다arrayList 처리하지만 참조 .
  3. (데이터가 전화 할 수있는 것보다 완전히 새로운 경우 항상 ArrayList를 자체 데이터를 수정 adapter.clear()하고 arrayList.clear()있지만, 새로운 데이터가 채워집니다 경우 어댑터 예를 설정하지 전에 실제로 목록에 데이터를 추가) arrayList보다는 다만 adapter.notifyDataSetChanged()

도움이 되었기를 바랍니다.


1
감사! # 2의 팁이 도움이되었습니다.
Cheruby

4

ListView를 새로 고칠 수도 있습니다.

receiptsListView.invalidate().

편집 : 또 다른 생각이 내 마음에 떠올랐다. 기록을 위해 목록보기 캐시를 비활성화하십시오.

<ListView
    ...
    android:scrollingCache="false"
    android:cacheColorHint="@android:color/transparent"
    ... />

이상하게도 마지막 아이디어는 데이터가 변경된 후 목록보기에 어댑터를 다시 할당하는 것입니다. 그러나 나는 당신이 이미 이것을 시도했다고 생각합니다.
Rafal Gałka 2013 년

3

나는 사용하여 같은 문제가 있었다 ListAdapter

나는 Android Studio가 나를 위해 메소드를 구현하게했고 이것이 내가 얻은 것입니다.

public class CustomAdapter implements ListAdapter {
    ...
    @Override
    public void registerDataSetObserver(DataSetObserver observer) {

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {

    }
    ...
}

문제는 이러한 메서드가 super구현을 호출하지 않으므로 호출 notifyDataSetChange되지 않는다는 것입니다.

이러한 재정의를 수동으로 제거하거나 수퍼 호출을 추가하면 다시 작동합니다.

@Override
public void registerDataSetObserver(DataSetObserver observer) {
    super.registerDataSetObserver(observer);
}

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
    super.unregisterDataSetObserver(observer);
}

2
class StudentAdapter extends BaseAdapter {
    ArrayList<LichHocDTO> studentList;

    private void capNhatDuLieu(ArrayList<LichHocDTO> list){
        this.studentList.clear();
        this.studentList.addAll(list);
        this.notifyDataSetChanged();
    }
}

당신은 시도 할 수 있습니다. 그것은 나를 위해 일합니다



1

우연히이 스레드에 도착하여 왜 adapter.invaidate()또는 adapter.clear()방법이 귀하의 경우에 존재하지 않는지 궁금 하다면 이 질문의 질문자가 사용하는 RecyclerView.Adapter대신 사용할 수 있기 때문일 수 있습니다 BaseAdapter. 을 삭제하는 경우 list또는 arraylist하지이 문제를 해결 당신이 만드는 것을 발생할 수 있습니다 인스턴스를 두 개 이상 의를 adapter전을 위해 :

주요 활동

...

adapter = new CustomAdapter(list);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);

...


SomeFragment

...

adapter = new CustomAdapter(newList);
adapter.notifyDataSetChanged();

...

두 번째 경우에 리사이클 러 뷰의 부풀린 뷰 목록이 변경 될 것으로 예상하는 경우 리사이클 러 뷰에 연결되지 않은의 새 인스턴스가 두 번째 adapter로 생성 될 때처럼 발생 하지 않습니다. notifyDataSetChanged두 번째 어댑터의 설정 은 recycer보기의 내용을 변경하지 않습니다. 이를 위해 SomeFragment 에서 리사이클 러 뷰 의 새 인스턴스를 만들고 어댑터의 새 인스턴스에 연결합니다.

SomeFragment

...

recyclerView = new RecyclerView();
adapter = new CustomAdapter();
recyclerView.setAdapter(adapter);

...

하지만 동일한 어댑터 및 리사이클 러 뷰의 여러 인스턴스를 만드는 것은 권장하지 않습니다.


0

이 코드 추가

runOnUiThread(new Runnable() { public void run() {
               adapter = new CustomAdapter(anotherdata);
            adapter.notifyDataSetChanged();
            }
        });

0

나도 같은 문제가 있는데 방금 끝냈어 !!

당신은 변경해야합니다

public class ReceiptListAdapter extends BaseAdapter {

    public List<Receipt> receiptlist;
    private Context context;
    private LayoutInflater inflater;
    private DateHelpers dateH;
    private List<ReceiptViewHolder> receiptviewlist;

    public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
        context = mcontext;
        receiptlist = rl;
        receiptviewlist = new ArrayList<>();
        receiptviewlist.clear();
        for(int i = 0; i < receiptlist.size(); i++){
          ReceiptViewHolder receiptviewholder = new ReceiptViewHolder();
          receiptviewlist.add(receiptviewholder);
        }
        Collections.reverse(receiptlist);
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        dateH = new DateHelpers();
    }

    @Override
    public int getCount() {
        try {
            int size = receiptlist.size();
            return size;
        } catch(NullPointerException ex) {
            return 0;
        }
    }

    public void updateReceiptsList(List<Receipt> newlist) {
        receiptlist = newlist;
        this.notifyDataSetChanged();
    }

    @Override
    public Receipt getItem(int i) {
        return receiptlist.get(i);
    }

    @Override
    public long getItemId(int i) {
        return receiptlist.get(i).getReceiptId() ;
    }

    private String getPuntenString(Receipt r) {
        if(r.getPoints().equals("1")) {
            return "1 punt";
        }
        return r.getPoints()+" punten";
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View vi=convertView;

        final Receipt receipt = receiptlist.get(position);
        ReceiptViewHolder receiptviewholder;
        Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");        
        Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf");

        if (vi == null) { //convertview==null
            ReceiptViewHolder receiptviewholder = receiptviewlist.get(position);
            vi = inflater.inflate(R.layout.view_listitem_receipt, null);
            vi.setOnClickListener(null);
            vi.setOnLongClickListener(null);
            vi.setLongClickable(false);
            receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop);
            receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date);
            receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price);
            receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points);
            receiptviewholder.shop.setTypeface(tf_hn_bold);
            receiptviewholder.price.setTypeface(tf_hn_bold);
            vi.setTag(receiptviewholder);
        }else{//convertview is not null
            receiptviewholder = (ReceiptViewHolder)vi.getTag();
        }

        receiptviewholder.shop.setText(receipt.getShop());
        receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate())));
        receiptviewholder.price.setText("€ "+receipt.getPrice());
        receiptviewholder.points.setText(getPuntenString(receipt));

        vi.setClickable(false);
        return vi;
    }

    public static class ReceiptViewHolder {
        public TextView shop;
        public TextView date;
        public TextView price;
        public TextView points;
    }

    public Object getFilter() {
        // XXX Auto-generated method stub
        return null;
    }

}

0

제 사건은 달랐지만 다른 사람들에게는 같은 사건 일 수 있습니다

여전히 해결책을 찾지 못하고 위의 모든 것을 시도한 사람들을 위해 조각 내부에서 어댑터를 사용하는 경우 작동하지 않는 이유 fragment could be recreating so the adapter is recreating everytime the fragment recreate

초기화하기 전에 어댑터 및 개체 목록이 null인지 확인해야합니다.

if(adapter == null){
  adapter = new CustomListAdapter(...);
}
...

if(objects == null){
  objects = new ArrayList<>();
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.