NotifyDataSetChange 在自定义适配器中无法工作

当我重新填充我的 ListView时,我从我的 Adapter中调用一个特定的方法。

问题 :

当我从我的 Adapter调用 updateReceiptsList时,数据被刷新,但是我的 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-);

起作用了,但不是它应该起作用的方式。

197326 次浏览

也许可以尝试刷新你的 ListView:

receiptsListView.invalidate().

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

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

改变你的方法

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

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

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

我也有同样的问题,我意识到了。当我们创建适配器并将其设置为 listview 时,listview 将指向适配器保存的内存中的某个对象,该对象中的数据将显示在 listview 中。

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

如果我们再次为带有另一个数据的适配器创建一个对象并通知 datasetchange () :

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

这不会影响 listview 中的数据,因为列表指向的是不同的对象,该对象不知道适配器中的新对象,并且 notifyDataSetChanged ()不会影响任何东西。 因此,我们应该更改对象中的数据,并避免再次为适配器创建新对象

我在使用 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);
}

正如我已经解释了背后的原因,这个问题,以及如何处理它在一个不同的答案线程 给你。我仍然在这里分享解决方案摘要。

notifyDataSetChanged()不适合你的一个主要原因是,

您的适配器将丢失对列表的引用。

当创建和添加一个新的列表到 Adapter。始终遵循以下指导方针:

  1. 初始化 arrayList,同时在全球范围内声明它。
  2. 直接将 List 添加到适配器,不检查 null 和 null 直接将适配器设置为列表(不要检查任何 条件)。适配器保证你,无论你做 改变 arrayList的数据,它会照顾它,但永远不会失去 参考文献。
  3. 始终修改 arrayList 本身中的数据(如果数据是全新的) 你可以调用 adapter.clear()arrayList.clear()之前 实际向列表中添加数据) ,但不要设置适配器 在 arrayList中填充的新数据不仅仅是 adapter.notifyDataSetChanged()

希望这个能帮上忙。

添加这个代码

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

如果 adapter设置为 AutoCompleteTextView,那么 notifyDataSetChanged()就不工作。

需要更新适配器:

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

class StudentAdapter extends BaseAdapter {
ArrayList<LichHocDTO> studentList;


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

你可以试试,对我有用

我也有同样的问题 但是我刚刚完成了! !

你应该换成

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


}

如果有任何机会,你降落在这个线程,并想知道为什么 adapter.invaidate()adapter.clear()方法不存在于你的情况下,那么可能是因为你可能使用 RecyclerView.Adapter而不是 BaseAdapter,这是问这个问题的人使用。如果清除 listarraylist没有解决你的问题,那么它可能会发生,你正在使 adapter两个或多个实例为例:

主要活动

...


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


...

还有
一些碎片

...


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


...

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

一些碎片

...


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


...

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

我的情况是不同的,但它可能是同样的情况下,其他人

对于那些仍然找不到解决方案并尝试了上述所有方法的人来说,如果您正在使用片段内部的适配器,那么它无法工作的原因就是 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<>();
}

在我的例子中,我只是忘记添加片段 mRecyclerView.setAdapter(adapter)

我犯了一个非常愚蠢的错误,在像这样初始化适配器本身之前,我正在设置回收视图的适配器。

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

切换线路解决了我的问题。

    oneOffJobTasksListRVAdapter = new OneOffJobTasksListRVAdapter();
recyclerView.setAdapter(oneOffJobTasksListRVAdapter);

如果使用自定义适配器,则必须添加

@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}

转换为自定义适配器方法后,只需在更改数据后调用 notifyDataSetChanged(),如替换、删除或添加新项

ArrayList <String> items;
int position=1;
items.set(position,"Changed Item");
items.remove(position);
items.add("New item");
notifyDataSetChanged();