144

当我重新填充我ListViewAdapter.

问题

当我updateReceiptsList从 my调用时Adapter,数据会刷新,但 myListView不会反映更改。

问题

为什么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();
}

因此,您在适配器中保留与 DataSet 相同的对象。

于 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()对您不起作用的主要原因之一是,

您的适配器失去了对您的列表的引用

在创建新列表并将其添加到Adapter. 始终遵循以下准则:

  1. arrayList在全局声明时初始化。
  2. 直接将 List 添加到适配器,而不检查 null 和空值。直接将适配器设置到列表中(不检查任何条件)。适配器向您保证,无论您对数据进行更改,arrayList它都会处理它,但永远不会丢失引用。
  3. 始终修改 arrayList 本身中的数据(如果您的数据是全新的,而不是您可以调用adapter.clear()并且arrayList.clear()在实际将数据添加到列表之前),但不要设置适配器,即如果新数据填充arrayListadapter.notifyDataSetChanged()

希望这可以帮助。

于 2016-08-01T06:37:34.553 回答
4

也许尝试刷新您的 ListView:

receiptsListView.invalidate().

编辑:另一个想法出现在我的脑海中。只是为了记录,尝试禁用列表视图缓存:

<ListView
    ...
    android:scrollingCache="false"
    android:cacheColorHint="@android:color/transparent"
    ... />
于 2013-03-15T00:18:37.180 回答
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 回答
2
class StudentAdapter extends BaseAdapter {
    ArrayList<LichHocDTO> studentList;

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

你可以试试。它对我有用

于 2019-01-27T17:32:44.773 回答
1

如果adapter设置为AutoCompleteTextViewnotifyDataSetChanged()不起作用。

需要这个来更新适配器:

myAutoCompleteAdapter = new ArrayAdapter<String>(MainActivity.this, 
        android.R.layout.simple_dropdown_item_1line, myList);

myAutoComplete.setAdapter(myAutoCompleteAdapter);

参考:http ://android-er.blogspot.in/2012/10/autocompletetextview-with-dynamic.html

于 2017-12-13T09:26:24.513 回答
1

如果您有任何机会登陆该线程并想知道为什么adapter.invaidate()adapter.clear()方法不存在于您的案例中,那么可能是因为您可能正在使用该问题的提问者使用的RecyclerView.Adapter而不是使用的方法。BaseAdapter如果清除listarraylist没有解决您的问题,那么您可能正在制作两个或多个for adapterex. 实例:

主要活动

...

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

...


一些片段

...

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

...

如果在第二种情况下,您期望回收器视图中的膨胀视图列表发生变化,那么它不会发生,因为在第二次adapter创建未附加到回收器视图的新实例时。第二个适配器中的设置notifyDataSetChanged不会改变回收站视图的内容。为此,在SomeFragment中创建一个回收器视图的新实例并将其附加到适配器的新实例。

一些片段

...

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

...

虽然,我不建议创建同一个适配器和回收器视图的多个实例。

于 2019-05-30T11:37:12.040 回答
0

就我而言,我只是忘记添加我的片段mRecyclerView.setAdapter(adapter)

于 2020-11-22T21:00:01.253 回答
0

我犯了一个非常菜鸟的错误,我在像这样初始化适配器本身之前设置了 RecyclerView 的适配器。

    // Assuume oneOffJobTasksListRVAdapter is declared already 
    recyclerView.setAdapter(oneOffJobTasksListRVAdapter);        
    oneOffJobTasksListRVAdapter = new OneOffJobTasksListRVAdapter();

换行解决了我的问题。

    oneOffJobTasksListRVAdapter = new OneOffJobTasksListRVAdapter();
    recyclerView.setAdapter(oneOffJobTasksListRVAdapter);        
于 2021-04-01T22:01:11.027 回答
-1

添加此代码

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

我有同样的问题,但我刚刚完成它!

你应该改为

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

}
于 2019-05-16T08:24:05.740 回答
-1

我的情况不同,但其他人的情况可能相同

对于那些仍然找不到解决方案并尝试了上述所有方法的人,如果您在片段中使用适配器,那么它无法正常工作的原因fragment could be recreating so the adapter is recreating everytime the fragment recreate

您应该在初始化之前验证适配器和对象列表是否为空

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

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

于 2020-04-24T13:56:03.003 回答