ListView
を再設定するとき、Adapter
から特定のメソッドを呼び出します。
問題:
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-);
動作しますが、動作するはずではありません。
メソッドを変更します
public void updateReceiptsList(List<Receipt> newlist) {
receiptlist = newlist;
this.notifyDataSetChanged();
}
に
public void updateReceiptsList(List<Receipt> newlist) {
receiptlist.clear();
receiptlist.addAll(newlist);
this.notifyDataSetChanged();
}
したがって、アダプタにはDataSetと同じオブジェクトを保持します。
私は同じ問題を抱えており、それを実現しています。アダプタを作成してリストビューに設定すると、リストビューはアダプタが保持するメモリ内のどこかのオブジェクトをポイントし、このオブジェクトのデータはリストビューに表示されます。
adapter = new CustomAdapter(data);
listview.setadapter(adapter);
別のデータを使用してアダプターのオブジェクトを再度作成し、notifydatasetchanged()した場合:
adapter = new CustomAdapter(anotherdata);
adapter.notifyDataSetChanged();
リストは別のオブジェクトを指しているため、リストビューのデータには影響しません。このオブジェクトはアダプターの新しいオブジェクトについて何も知らず、notifyDataSetChanged()は何にも影響しません。そのため、オブジェクトのデータを変更し、アダプター用の新しいオブジェクトを再度作成しないようにする必要があります
すでにこの問題の背後にある理由と、別の回答スレッドでそれを処理する方法について説明したように Here 。それでも、ここでソリューションの概要を共有しています。
notifyDataSetChanged()
が機能しない主な理由の1つは、
アダプタはリストへの参照を失います。
新しいリストを作成してAdapter
に追加するとき。常に次のガイドラインに従ってください。
arrayList
を初期化します。arrayList
のデータをどこで変更してもそれが処理されることを保証しますが、参照を失うことはありません。adapter.clear()
およびarrayList.clear()
を呼び出すことができます)が、アダプターを設定しないでください。つまり、新しいデータがadapter.notifyDataSetChanged()
だけでなくarrayList
に設定されている場合お役に立てれば。
たぶんあなたのリストビューを更新してみてください:
receiptsListView.invalidate()
。
編集:別の考えが頭に浮かんだ。記録のために、リストビューキャッシュを無効にしてみてください。
<ListView
...
Android:scrollingCache="false"
Android:cacheColorHint="@Android:color/transparent"
... />
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);
}
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();
}
}
あなたが試すことができます。それは私のために働く
このコードを追加
runOnUiThread(new Runnable() { public void run() {
adapter = new CustomAdapter(anotherdata);
adapter.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()
メソッドがあなたのケースに存在しないのか疑問に思ったなら、おそらくこの質問の質問者が使用するBaseAdapter
の代わりにRecyclerView.Adapter
を使用している可能性があります。 list
またはarraylist
をクリアしても問題が解決しない場合は、たとえば、adapter
の2つ以上のインスタンスを作成している可能性があります。
MainActivity
...
adapter = new CustomAdapter(list);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
...
そして
SomeFragment
...
adapter = new CustomAdapter(newList);
adapter.notifyDataSetChanged();
...
2番目の場合、リサイクラービューの拡張されたビューのリストの変更が予想される場合、2回目は、リサイクラービューにアタッチされていないadapter
の新しいインスタンスが作成されるため、起こりません。 2番目のアダプターでnotifyDataSetChanged
を設定しても、recycerビューの内容は変更されません。そのためには、SomeFragmentでリサイクラビューの新しいインスタンスを作成し、それをアダプタの新しいインスタンスにアタッチします。
SomeFragment
...
recyclerView = new RecyclerView();
adapter = new CustomAdapter();
recyclerView.setAdapter(adapter);
...
ただし、同じアダプターおよびリサイクラビューの複数のインスタンスを作成することはお勧めしません。