144

my を再作成するとき、ListViewmy から特定のメソッドを呼び出しますAdapter

問題:

updateReceiptsListmy から呼び出すとAdapter、データは更新されますが、my に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-);

動作しますが、動作するはずの方法ではありません。

4

13 に答える 13

358

メソッドをから変更します

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

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

したがって、アダプタ内のデータセットと同じオブジェクトを保持します。

于 2013-03-15T08:28:01.897 に答える
26

私は同じ問題を抱えており、それを認識しています。アダプターを作成してリストビューに設定すると、リストビューはアダプターが保持するメモリ内のどこかにあるオブジェクトを指し、このオブジェクトのデータがリストビューに表示されます。

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

別のデータを使用してアダプターのオブジェクトを再度作成し、notifydatasetchanged() を作成すると、次のようになります。

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

リストは別のオブジェクトを指しており、このオブジェクトはアダプターの新しいオブジェクトについて何も知らず、notifyDataSetChanged() は何も影響しないため、これはリストビューのデータには影響しません。したがって、オブジェクトのデータを変更し、アダプター用に新しいオブジェクトを再度作成しないようにする必要があります

于 2014-04-21T10:31:19.793 に答える
20

この問題の背後にある理由と、別の回答スレッドでそれを処理する方法については、ここで説明しました。それでも、ここでソリューションの概要を共有しています。

notifyDataSetChanged()うまくいかない主な理由の 1 つは、

アダプターはリストへの参照を失います

新しいリストを作成して に追加するときAdapter。常に次のガイドラインに従ってください。

  1. arrayListグローバルに宣言しながら初期化します。
  2. null および空の値をチェックせずに、List をアダプタに直接追加します。アダプターをリストに直接設定します (条件をチェックしないでください)。Adapter は、 のデータをどこで変更しても、arrayListそれが処理され、参照が失われないことを保証します。
  3. 常にarrayList自体のデータを変更します(データが完全に新しい場合は、実際にリストにデータを追加する前に呼び出すことができます) adapter.clear()arrayList.clear()、アダプターを設定しないでください。つまり、新しいデータがarrayListadapter.notifyDataSetChanged()

お役に立てれば。

于 2016-08-01T06:37:34.553 に答える
4

私は使用して同じ問題を抱えていました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);
}
于 2015-12-22T10:10:22.647 に答える
4

ListView を更新してみてください:

receiptsListView.invalidate().

編集:別の考えが頭に浮かびました。念のため、リスト ビュー キャッシュを無効にしてみてください。

<ListView
    ...
    android:scrollingCache="false"
    android:cacheColorHint="@android:color/transparent"
    ... />
于 2013-03-15T00:18:37.180 に答える
0

私の場合、フラグメントを追加するのを忘れるだけですmRecyclerView.setAdapter(adapter)

于 2020-11-22T21:00:01.253 に答える
-1

私のケースは違いましたが、他の人にとっては同じケースかもしれません

それでも解決策を見つけることができず、上記のすべてを試した場合、フラグメント内でアダプターを使用している場合、それが機能しない理由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<>();
}

于 2020-04-24T13:56:03.003 に答える
-1

このコードを追加

runOnUiThread(new Runnable() { public void run() {
               adapter = new CustomAdapter(anotherdata);
            adapter.notifyDataSetChanged();
            }
        });
于 2017-03-22T10:32:17.070 に答える