删除Firestore数据后ListView无法刷新的问题求助
问题:ListView删除Firestore数据后无法刷新界面
我在NotesLVAdapter中添加了OnLongClickListener,长按ListView列表项会弹出菜单,点击删除选项可将对应项从Firestore数据库移除,但删除后ListView不会刷新,该项依然停留在界面上。使用notifyDataSetChanged()添加新项时有效,但删除操作时完全没效果。
相关代码
ListView所在Activity代码
private ArrayList<String> notes = new ArrayList<String>(); private ArrayAdapter<String> arrayAdapter; private ListView listView; private FirebaseFirestore db; private static final String TAG="ALMA"; private ArrayList<Notes> allNotes; private ArrayList<Notes> noNotes= new ArrayList<>(); private String mail; private FloatingActionButton floatingbtn; private NotesLVAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_notes_lv); listView = (ListView) findViewById(R.id.listView); floatingbtn = (FloatingActionButton) findViewById(R.id.floatingActionButton); floatingbtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(NotesLV.this, CreateNote.class); startActivity(intent); } }); FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); mail = user.getEmail().toString(); allNotes = new ArrayList<>(); db = FirebaseFirestore.getInstance(); adapter = new NotesLVAdapter(NotesLV.this, allNotes); listView.setAdapter(adapter); } public void loadNotesToListView(){ allNotes.clear(); adapter.notifyDataSetChanged(); Log.d(TAG,"loading"); db.collection("Folder").document(mail).collection("Notes").orderBy("date",Query.Direction.DESCENDING).get() .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() { @Override public void onSuccess(QuerySnapshot queryDocumentSnapshots) { if (!queryDocumentSnapshots.isEmpty()) { List<DocumentSnapshot> list = queryDocumentSnapshots.getDocuments(); Log.d(TAG, "List size: " + list.size()); for (DocumentSnapshot d : list) { Notes notes = d.toObject(Notes.class); d.getId(); allNotes.add(notes); Log.d(TAG, "added"); } adapter = new NotesLVAdapter(NotesLV.this, allNotes); listView.setAdapter(adapter); Log.d(TAG, "adapter was set"); } else { Log.d(TAG,"No data found in query"); Toast.makeText(NotesLV.this, "No data found in Database", Toast.LENGTH_SHORT).show(); } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(NotesLV.this, "Fail to load data..", Toast.LENGTH_SHORT).show(); } }); } @Override protected void onResume() { super.onResume(); adapter.notifyDataSetChanged(); loadNotesToListView(); }
Adapter代码
private FirebaseFirestore db; private String mail; public NotesLVAdapter(Context context, ArrayList<Notes> notes) { super(context, 0, notes); } @Override public View getView(int position, View convertView, ViewGroup parent) { View listItemView = convertView; if (listItemView==null) { listItemView = LayoutInflater.from(getContext()).inflate(R.layout.activity_notes_d,parent, false); } Notes notes = getItem(position); db= FirebaseFirestore.getInstance(); FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); mail= user.getEmail().toString(); TextView tvNTitle = (TextView) listItemView.findViewById(R.id.tvNoteName); tvNTitle.setText(notes.getNoteName()); TextView tvNDate = (TextView) listItemView.findViewById(R.id.tvDate); tvNDate.setText(notes.getSavedDate()); ImageView imageBoss=(ImageView)listItemView.findViewById(R.id.imgBoss); String pic=""; listItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d("ALMA","clicked"); Intent intent = new Intent(view.getContext(), CreateNote.class); intent.putExtra("title",tvNTitle.getText().toString()); intent.putExtra("content",notes.getContent().toString()); intent.putExtra("reminder",notes.needReminder()); intent.putExtra("saved date",notes.getSavedDate().toString()); intent.putExtra("date",notes.getDate().toString()); view.getContext().startActivity(intent); } }); listItemView.setOnLongClickListener(new AdapterView.OnLongClickListener() { @Override public boolean onLongClick(View view) { PopupMenu popupMenu=new PopupMenu(view.getContext(), view); popupMenu.setGravity(Gravity.END); popupMenu.getMenuInflater().inflate(R.menu.notes_popup_menu,popupMenu.getMenu()); popupMenu.show(); popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ @Override public boolean onMenuItemClick(MenuItem menuItem) { int id=menuItem.getItemId(); if(id==R.id.menu_edit) { Intent intent = new Intent(view.getContext(), CreateNote.class); intent.putExtra("title",tvNTitle.getText().toString()); intent.putExtra("content",notes.getContent().toString()); intent.putExtra("reminder",notes.needReminder()); intent.putExtra("date",notes.getDate().toString()); view.getContext().startActivity(intent); } if(id==R.id.menu_delete){ db.collection("Folder").document(mail).collection("Notes").document(notes.getNoteName()+", "+notes.getSavedDate()).delete() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { Log.d("ALMA","deleted"); } else { Log.d("ALMA","didnt delete"); } } }); } return true; } }); return true; } }); return listItemView; }
问题原因及解决方案
1. 核心问题
删除Firestore数据后,仅修改了云端数据,但本地数据源allNotes未移除对应项,也未调用notifyDataSetChanged()通知Adapter更新界面;同时loadNotesToListView方法每次都会重新创建Adapter实例,导致原Adapter引用失效。
2. 修复步骤
步骤1:在Adapter删除回调中更新本地数据源并通知刷新
修改Adapter中删除逻辑,在云端删除成功后,移除本地数据源的对应项并通知Adapter:
if(id==R.id.menu_delete){ db.collection("Folder").document(mail).collection("Notes").document(notes.getNoteName()+", "+notes.getSavedDate()).delete() .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { if (task.isSuccessful()) { Log.d("ALMA","deleted"); // 移除本地数据源中的当前项 remove(notes); // 通知Adapter刷新界面 notifyDataSetChanged(); } else { Log.d("ALMA","didnt delete"); } } }); }
步骤2:优化loadNotesToListView的Adapter复用逻辑
不再每次创建新Adapter,复用已初始化的Adapter实例,仅更新数据源后通知刷新:
public void loadNotesToListView(){ allNotes.clear(); Log.d(TAG,"loading"); db.collection("Folder").document(mail).collection("Notes").orderBy("date",Query.Direction.DESCENDING).get() .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() { @Override public void onSuccess(QuerySnapshot queryDocumentSnapshots) { if (!queryDocumentSnapshots.isEmpty()) { List<DocumentSnapshot> list = queryDocumentSnapshots.getDocuments(); Log.d(TAG, "List size: " + list.size()); for (DocumentSnapshot d : list) { Notes notes = d.toObject(Notes.class); allNotes.add(notes); Log.d(TAG, "added"); } // 复用现有Adapter,直接通知刷新 adapter.notifyDataSetChanged(); Log.d(TAG, "data refreshed"); } else { Log.d(TAG,"No data found in query"); Toast.makeText(NotesLV.this, "No data found in Database", Toast.LENGTH_SHORT).show(); adapter.notifyDataSetChanged(); // 空数据时也要通知刷新 } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(NotesLV.this, "Fail to load data..", Toast.LENGTH_SHORT).show(); } }); }
步骤3:调整onResume中的重复刷新逻辑
移除重复的loadNotesToListView调用,避免界面频繁闪烁:
@Override protected void onResume() { super.onResume(); // 仅通知Adapter刷新即可,无需每次重新拉取数据 adapter.notifyDataSetChanged(); }
可选优化:使用Firestore实时监听
如果需要界面实时同步云端数据,可使用addSnapshotListener替代get(),数据变化时自动更新界面:
// 在Activity的onCreate中添加实时监听 db.collection("Folder").document(mail).collection("Notes").orderBy("date",Query.Direction.DESCENDING) .addSnapshotListener(new EventListener<QuerySnapshot>() { @Override public void onEvent(@Nullable QuerySnapshot value, @Nullable FirebaseFirestoreException error) { if (error != null) { Log.w(TAG, "Listen failed.", error); return; } allNotes.clear(); for (DocumentSnapshot doc : value) { Notes notes = doc.toObject(Notes.class); allNotes.add(notes); } adapter.notifyDataSetChanged(); } });
内容的提问来源于stack exchange,提问作者Alma
相关产品推荐
相关产品推荐

