notifyDataSetChange özel adaptörden çalışmıyor


126

Yeniden doldurduğumda ListView, kendimden belirli bir yöntemi çağırırım Adapter.

Sorun :

updateReceiptsListBenim telefonumdan aradığımda Adapterveriler yenileniyor, ancak benimki ListViewdeğişikliği yansıtmıyor.

Soru :

ListViewAradığımda neden yeni verileri göstermiyor notifyDataSetChanged?

Adaptör :

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

}

--DÜZENLE:

Geçici çözüm bulundu

Sadece şimdi yaptığım bazı işlevsel kodlara sahip olmak için:

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

Çalışır, ama olması gerektiği gibi değil.


stackoverflow.com/a/4198569/2382964 , Merhaba Jasper lütfen bu bağlantıya bakın ... bu size yardımcı olacaktır.
Tushar Pandey

notifyItemInserted, notifyItemRemoved, vb. gibi diğer yöntemleri deneyin.
Reejesh PK

Yanıtlar:


334

Yönteminizi şundan değiştirin:

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

için

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

Böylece DataSet'inizle aynı nesneyi Adaptörünüzde tutarsınız.


nesneler ReceiptListObjectyerine bir üst nesneye sahip olmayı düşünün, Listbu sorunu çözmek için ne yapabilirsiniz?
prom85

@ prom85 ArrayAdapters, Listeler veya Diziler dışındaki Nesnelere bile bağlanabilir mi? Bilmiyordum.
tolgap

Bu a BaseAdapterile ilgili ve bu bağdaştırıcı hangi verilere bağlandığını bilmiyor ... bu yüzden özel bir nesnem varsa ve bu nesnenin özel işlevlerini (örneğin custObject.getCount()ve custObject.getChildAt(int i)örneğin) kullanırsam ve bu nesneyi değiştirmek istersem notifyDataSetChangedçalışmıyor ... her neyse, bence bu sorun birArrayAdapter
baloda

3
İlk yöntemin neden çalışmadığını ve ikincisinin BaseAdapter ile çalıştığını açıklayabilir misiniz?
Tooroop

1
Teşekkürler veya +1 gibi yorumlara izin verilmiyor ancak bazı yanıtlarda teşekkür etmeyi çok seviyorum :)
Muhammad Saqib

24

Bende de aynı sorun var ve bunun farkındayım. Bağdaştırıcı oluşturup listview olarak ayarladığımızda, listview bağdaştırıcının tuttuğu bellekte bir yerdeki nesneyi işaret edecek, bu nesnedeki veriler liste görünümünde gösterilecektir.

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

adaptör için tekrar başka bir veriyle bir nesne oluşturur ve notifydatasetchanged ():

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

liste farklı bir nesneyi işaret ettiğinden, bu nesne bağdaştırıcıdaki yeni nesne hakkında hiçbir şey bilmediğinden ve notifyDataSetChanged () hiçbir şeyi etkilemediğinden listview'deki verileri etkilemeyecektir. Bu yüzden nesnedeki verileri değiştirmeli ve adaptör için tekrar yeni bir nesne oluşturmaktan kaçınmalıyız


10
adaptör nesnesini yeniden oluşturuyorsunuz, bu verimli değil
Alezis

2
@Alezis Bence Nhan'ın kastettiği tam olarak bu.
Neeraj Sewani

17

Bu sorunun arkasındaki nedenleri ve bunun farklı bir cevap dizisinde nasıl ele alınacağını daha önce açıkladığım gibi burada . Yine de çözüm özetini burada paylaşıyorum.

Ana nedenlerden biri notifyDataSetChanged()sizin için işe yaramayacak - şudur,

Adaptörünüz listenize referans kaybediyor .

Yeni bir liste oluştururken ve Adapter. Daima şu yönergeleri izleyin:

  1. İlklendirin arrayListGlobal olarak bildirirken .
  2. Listeyi, boş ve boş değerleri kontrol etmeden doğrudan adaptöre ekleyin. Adaptörü doğrudan listeye ayarlayın (herhangi bir koşulu kontrol etmeyin). Adaptör size, verilerinde değişiklik yaptığınız her yerde arrayListbununla ilgileneceğini, ancak referansı asla kaybetmeyeceğini garanti eder .
  3. (Verileriniz Arayabileceğin daha tamamen yeni ise daima ArrayList kendisi verileri değiştirmek adapter.clear()ve arrayList.clear()ancak yeni veri doldurulur ise adaptör yani set yok önce aslında listesine veri ekleme) arrayListsadece daha adapter.notifyDataSetChanged()

Bu yardımcı olur umarım.


1
Teşekkürler! 2 numaradaki ipucu yardımcı oldu.
Cheruby

4

ListView'unuzu yenilemeyi deneyebilirsiniz:

receiptsListView.invalidate().

DÜZENLEME: Aklıma başka bir düşünce geldi. Sadece kayıt için, liste görünümü önbelleğini devre dışı bırakmayı deneyin:

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

Garip, son fikrim, veri değiştirildikten sonra bağdaştırıcıyı liste görünümüne yeniden atamak. Ama sanırım bunu da denedin.
Rafal Gałka

3

Ben de aynı sorunu yaşadım ListAdapter

Android Studio'nun benim için yöntemleri uygulamasına izin verdim ve sahip olduğum şey bu:

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

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {

    }
    ...
}

Sorun, bu yöntemlerin superuygulamaları çağırmamasıdır.notifyDataSetChange asla çağrılmaz.

Bu geçersiz kılmaları manuel olarak kaldırın veya süper aramalar ekleyin ve tekrar çalışması gerekir.

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

Deneyebilirsin. Benim için çalışıyor



1

Herhangi bir şans eseri bu konuya girdiyseniz ve neden adapter.invaidate()veya adapter.clear()yöntemlerin sizin durumunuzda bulunmadığını merak ettiyseniz, o zaman belki de bu soruyu soran tarafından RecyclerView.Adapterbunun yerine BaseAdapterhangisini kullanıyor olabilirsiniz . Sorununuzu gideriyorsanız listveya arraylistçözmüyorsa, örneğin for'un iki veya daha fazla örneğini oluşturuyor olabilirsiniz adapter:

Ana aktivite

...

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

...

ve
SomeFragment

...

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

...

İkinci durumda, geri dönüşümcü görünümündeki şişirilmiş görünümler listesinde bir değişiklik bekliyorsanız, ikinci kez geri dönüşümcü görünümüne eklenmeyen yeni bir örneği adapteroluşturulduğu için bu gerçekleşmeyecektir. notifyDataSetChangedİkinci adaptörün ayarlanması , geri dönüşüm görünümünün içeriğini değiştirmeyecektir. Bunun için, SomeFragment'ta geri dönüşümcü görünümünün yeni bir örneğini oluşturun ve bunu adaptörün yeni örneğine ekleyin.

SomeFragment

...

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

...

Yine de, aynı adaptör ve geri dönüşümcü görünümünün birden çok örneğini oluşturmanızı önermiyorum.


0

Bu kodu ekleyin

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

0

Bende de aynı sorun var ama yeni bitirdim !!

değişmelisin

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

Benim durumum farklıydı ama diğerleri için aynı durum olabilir

Hala bir çözüm bulamayan ve yukarıdaki her şeyi deneyenler için, adaptörü parçanın içinde kullanıyorsanız, o zaman çalışmama nedeni fragment could be recreating so the adapter is recreating everytime the fragment recreate

başlatmadan önce adaptör ve nesne listesinin boş olup olmadığını doğrulamalısınız

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

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.