[英]RecyclerView does not update after removing an item from the Firestore
我正在開發一個程序,它從 Firestore 讀取所有文檔並將它們加載到 RecyclerView 中。 這完美地工作,但是當我嘗試做相反的事情時,即從 Firestore 中刪除一個文檔,后者不會起飛,它停留在 RecyclerView 中。 為了得到它,我必須將 go 轉到另一個屏幕,然后再回來。 下面我放代碼:
package project.dobus;
// Librerie.
import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.appcompat.widget.SearchView;
import com.google.firebase.firestore.DocumentChange;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.EventListener;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.FirebaseFirestoreException;
import com.google.firebase.firestore.QuerySnapshot;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class PassengerRequestPage extends AppCompatActivity { // Schermata per rifiutare e accettare le richieste degli user in attesa.
// Dichiarazioni oggetti globali: devono essere visti fuori da OnCreate.
RecyclerView recyclerView; // Schermata che contiene tutte le richieste.
ArrayList<PassengerPage> userArrayList; // Contiene tutte le informazioni relative all'user.
AdapterPassengerRequestPage myAdapter; // Oggetto di tipo AdapterPassengerRequestPage.
SearchView searchView; // Serve per cercare nella barra di ricerca un passeggero.
FirebaseFirestore Firestore; // Dichiarazione Database.
@Override
protected void onCreate(Bundle savedInstanceState) { // Alla creazione della schermata.
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_request_page); // Si collega con la schermata grafica activity_request_page.xml.
// Oggetti della schermata grafica.
Button backButton = findViewById(R.id.buttonback); // Bottone per tornare indietro nel pannello amministrativo.
recyclerView = findViewById(R.id.recyclerView); // Schermata che contiene tutte le richieste.
searchView = findViewById(R.id.searchviewRP); // Serve per cercare nella barra di ricerca un passeggero.
userArrayList = new ArrayList<>(); // Contiene tutte le informazioni relative all'user.
// Impostazioni del recyclerView.
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
myAdapter = new AdapterPassengerRequestPage(PassengerRequestPage.this,userArrayList);
recyclerView.setAdapter(myAdapter);
// Database.
Firestore = FirebaseFirestore.getInstance();
// Variabili memorizzate.
SharedPreferences variablesStored = getSharedPreferences("variablesStored", 0);
// Controlla costantemente se nel database, nella raccolta "Admins", è presente o no il numero.
DocumentReference usersDocumentsFirestore = Firestore.collection("Admins").document(variablesStored.getString("phoneNumber", "0"));
usersDocumentsFirestore.addSnapshotListener((usersDocument, usersError) -> {
if (usersError != null){
return;
}
if (usersDocument != null && !usersDocument.exists()) { // Se non dovesse più esistere ritorna in AccessPage.
Intent intent = new Intent(getApplicationContext(), AccessPage.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent); // Va in AccessPage.
}
});
// SearchView.
searchView.clearFocus(); // Leva il focus presente sulla searchView.
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) { // Quando si preme invio per cercare quello che si è scritto.
return false;
}
@Override
public boolean onQueryTextChange(String newText) { // Ogni volta che il testo cambia.
filterList(newText);
return true;
}
});
backButton.setOnClickListener(view -> { // Inizio: quando si clicca il bottone per tornare indietro nel pannello amministrativo.
Intent intent = new Intent(getApplicationContext(), AdministrativePanel.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent); // Ritorna nel pannello amministrativo.
}); // Fine: quando si clicca il bottone per tornare indietro nel pannello amministrativo.
eventUserAdded(); // Evneto che gestisce l'aggiunta di un user alla schermata.
}
@SuppressLint("NotifyDataSetChanged")
private void eventUserAdded() { // Inizio: Evento che gestisce l'aggiunta di un user alla schermata.
Firestore.collection("Attesa").addSnapshotListener((snapshots, e) -> {
if (e != null) return;
assert snapshots != null;
for (DocumentChange AttesaDocument : snapshots.getDocumentChanges()) {
switch (AttesaDocument.getType()) {
case ADDED: // Ogni volta che viene aggiunto un item nella schermata.
PassengerPage userData = AttesaDocument.getDocument().toObject(PassengerPage.class);
userData.setPassengerPhoneNumber(AttesaDocument.getDocument().getId()); // Setta il numero dell'user prendendolo dall'ID del documento.
userData.setPassengerName((String) AttesaDocument.getDocument().get("Nome")); // Setta il nome dell'user.
userData.setPassengerSurname((String) AttesaDocument.getDocument().get("Cognome")); // Setta il cognome dell'user.
userData.setPassengerSchool((String) AttesaDocument.getDocument().get("Scuola")); // Setta la scuola dell'user.
userArrayList.add(userData); // Aggiunge le informazioni dell'user dentro la lista.
myAdapter.notifyDataSetChanged(); // Avvisa che qualcosa è stato cambiato.
break;
case REMOVED: // Ogni volta che viene rimosso un item dalla schermata.
break;
}
}
});
} // Fine: Evento che gestisce l'aggiunta di un user alla schermata.
private void filterList(String text){ // Inizio: Metodo che permette di cercare nella recyclerView la parola che si scrive nella searchView.
ArrayList<PassengerPage> filteredList = new ArrayList<>();
for(PassengerPage item: userArrayList){
if(item.getPassengerName().toLowerCase().contains(text.toLowerCase()) || item.getPassengerSurname().toLowerCase().contains(text.toLowerCase()) || item.getPassengerPhoneNumber().contains(text)){
filteredList.add(item);
}
}
myAdapter.setFilteredList(filteredList);
} // Fine: Metodo che permette di cercare nella recyclerView la parola che si scrive nella searchView.
}
.
package project.dobus;
// Librerie
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class AdapterPassengerRequestPage extends RecyclerView.Adapter<AdapterPassengerRequestPage.MyViewHolder> { // Classe che gestisce il recycleView di PassengerRequestPage.
Context context;
// Lista che contiene tutte le informazioni del passeggero.
ArrayList<PassengerPage> userArrayList;
public AdapterPassengerRequestPage(Context context, ArrayList<PassengerPage> userArrayList) { // Inizio Costruttore.
this.context = context;
this.userArrayList = userArrayList;
} // Fine: Costruttore.
@NonNull
@Override
public AdapterPassengerRequestPage.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { // Inizio: Crea la view di PassengerRequestPage con il layout card_user.xml.
View requestPageView = LayoutInflater.from(context).inflate(R.layout.card_accept_user,parent,false);
return new MyViewHolder(requestPageView);
} // Fine: Crea la view di PassengerRequestPage con il layout card_user.xml.
@SuppressLint("NotifyDataSetChanged") // Serve per evitare un avviso con notifyDataSetChanged().
public void setFilteredList(ArrayList<PassengerPage> filteredList){ // Inizio: Metodo che aggiorna l'array dei passeggeri con quello flitrato.
this.userArrayList = filteredList;
notifyDataSetChanged();
} // Fine: Metodo che aggiorna l'array dei passeggeri con quello flitrato.
// Gestisce tutte le azioni che riguardano gli oggetti grafici.
@Override
public void onBindViewHolder(@NonNull AdapterPassengerRequestPage.MyViewHolder holder, int position) { // Inizio onBindViewHolder.
FirebaseFirestore Firestore = FirebaseFirestore.getInstance(); // Database Firestore.
PassengerPage passengerUser = userArrayList.get(position);
holder.passengerName.setText(passengerUser.passengerName); // Cambia il testo "passengerName" con il nome che prende dal database: viene assegnato in PassengerPage.
holder.passengerSurname.setText(passengerUser.passengerSurname); // Cambia il testo "passengerSurname" con il nome che prende dal database: viene assegnato in PassengerPage.
holder.passengerPhoneNumber.setText(passengerUser.passengerPhoneNumber); // Cambia il testo "passengerPhoneNumber" con il nome che prende dal database: viene assegnato in PassengerPage.
holder.passengerSchool.setText(passengerUser.passengerSchool); // Cambia il testo "passengerSchool" con il nome che prende dal database: viene assegnato in PassengerPage.
holder.declineUserButton.setOnClickListener(view -> { // Inizio: quando clicco il tasto per rifiutare un utente in attesa.
Firestore.collection("Attesa").document(passengerUser.passengerPhoneNumber).delete(); // Rimuove dal database l'utente.
// Permette di non crashare quando si preme a ripetizione il tasto per rifiutare un passeggero in attesa.
if (holder.getAdapterPosition() == RecyclerView.NO_POSITION) {
return;
}
userArrayList.remove(holder.getAdapterPosition()); // Rimuove dalla lista l'utente.
notifyItemRemoved(holder.getAdapterPosition()); // Avvisa che è stato rimosso l'utente e sistema la schermata.
}); // Fine: quando clicco il tasto per rifiutare un utente in attesa.
holder.acceptUserButton.setOnClickListener(view -> Firestore.collection("Attesa") // Inizio: quando si clicca il bottone per accettare un utente in attesa.
.get()
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot AttesaDocument : task.getResult()) {
Map<String, Object> userData = new HashMap<>(); // Serve a memorizzare tutte le informazioni dell'user.
userData.put("Nome", AttesaDocument.get("Nome")); // Aggiunge dentro userData il nome dell'user.
userData.put("Cognome", AttesaDocument.get("Cognome")); // Aggiunge dentro userData il cognome dell'user.
userData.put("Scuola", AttesaDocument.get("Scuola")); // Aggiunge dentro userData la scuola dell'user.
Firestore.collection("Users").document(passengerUser.passengerPhoneNumber).set(userData); // Aggiunge nella nuova collezione "Users" i nuovi dati.
Firestore.collection("Attesa").document(passengerUser.passengerPhoneNumber).delete(); // Rimuove da attesa i dati.
// Permette di non crashare quando si preme a ripetizione il tasto per accettare un passeggero in attesa.
if (holder.getAdapterPosition() == RecyclerView.NO_POSITION) {
return;
}
userArrayList.remove(holder.getAdapterPosition()); // Rimuove dalla lista l'utente.
notifyItemRemoved(holder.getAdapterPosition()); // Avvisa che è stato rimosso l'utente e sistema la schermata.
}
}
})); // Fine: quando si clicca il bottone per accettare un utente in attesa.
} // Fine onBindViewHolder.
// Conta i valori presenti nella lista.
@Override
public int getItemCount() {
return userArrayList.size();
}
// Gestisce gli elementi presenti nel file card_user.xml.
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView passengerName, passengerSurname, passengerPhoneNumber, passengerSchool; // Testo che contiene le informazioni del passeggero.
Button declineUserButton, acceptUserButton; // Bottoni per accettare e rifiutare le richieste.
public MyViewHolder(@NonNull View itemView) {
super(itemView);
passengerPhoneNumber = itemView.findViewById(R.id.idDocumento); // Oggetto grafico per il numero di telefono.
passengerName = itemView.findViewById(R.id.tvFirstName); // Testo per il nome dell'user.
passengerSurname = itemView.findViewById(R.id.tvLastName); // Testo per il cognome dell'user.
passengerSchool = itemView.findViewById(R.id.idScuola); // Testo per la scuola dell'user.
declineUserButton = itemView.findViewById(R.id.rimuoviButton); // Bottone per rifiutare l'user.
acceptUserButton = itemView.findViewById(R.id.okButton); // Bottone per per accettare l'user.
}
}
}
.
package project.dobus;
// Librerie.
import com.google.firebase.firestore.DocumentId;
public class PassengerPage { // Classe che serve per modificare le informazioni degli user in attesa.
String passengerName, passengerSurname, passengerPhoneNumber, passengerSchool; // Informazioni degli user.
// Costruttore vuoto.
public PassengerPage(){}
// Costruttore.
public PassengerPage(String passengerName, String passengerSurname, String passengerPhoneNumber) {
this.passengerName = passengerName;
this.passengerSurname = passengerSurname;
this.passengerPhoneNumber = passengerPhoneNumber;
}
public String getPassengerName() { return passengerName; } // Prende quello che contiene PassengerName.
public void setPassengerName(String passengerName) { this.passengerName = passengerName; } // Setta PassengerName con il nome dell'user.
public String getPassengerSurname() { return passengerSurname; } // Prende quello che contiene PassengerSurname.
public void setPassengerSurname(String passengerSurname) { this.passengerSurname = passengerSurname; } // Setta PassengerSurname con il cognome dell'user.
@DocumentId
public String getPassengerPhoneNumber() { return passengerPhoneNumber; } // Prende quello che contiene passengerName.
@DocumentId
public void setPassengerPhoneNumber(String passengerPhoneNumber) { this.passengerPhoneNumber = passengerPhoneNumber; } // Setta PassengerPhoneNumber con il numero dell'user.
public String getPassengerSchool() { return passengerSchool; } // Prende quello che contiene PassengerSchool.
public void setPassengerSchool(String passengerSchool) { this.passengerSchool = passengerSchool; } // Setta PassengerSchool con il numero dell'user.
}
如何修復代碼,以便當我從 Firestore 中刪除文檔時,它會自動從 RecyclerView 中實時刪除它?
我試着把
myAdapter.notifyDataSetChanged();
在這部分
case REMOVED:
/////
break;
但沒有任何改變..
問題在這里:
Firestore.collection("Attesa").addSnapshotListener((snapshots, e) -> {
if (e != null) return;
assert snapshots != null;
for (DocumentChange AttesaDocument : snapshots.getDocumentChanges()) {
switch (AttesaDocument.getType()) {
case ADDED: // Ogni volta che viene aggiunto un item nella schermata.
PassengerPage userData = AttesaDocument.getDocument().toObject(PassengerPage.class);
userData.setPassengerPhoneNumber(AttesaDocument.getDocument().getId()); // Setta il numero dell'user prendendolo dall'ID del documento.
userData.setPassengerName((String) AttesaDocument.getDocument().get("Nome")); // Setta il nome dell'user.
userData.setPassengerSurname((String) AttesaDocument.getDocument().get("Cognome")); // Setta il cognome dell'user.
userData.setPassengerSchool((String) AttesaDocument.getDocument().get("Scuola")); // Setta la scuola dell'user.
userArrayList.add(userData); // Aggiunge le informazioni dell'user dentro la lista.
myAdapter.notifyDataSetChanged(); // Avvisa che qualcosa è stato cambiato.
break;
case REMOVED: // Ogni volta che viene rimosso un item dalla schermata.
break;
}
}
您正在使用實時偵聽器,這意味着每當刪除文檔(或Attesa
中的任何其他更改)時,您的代碼都會收到通知。但是您的代碼僅處理初始文檔和添加內容,並主動忽略文檔的刪除或更改現有文件。
您需要處理所有三種事件類型:
ADDED
:通過從快照中獲取數據並將其添加到您的userArrayList
來處理此問題(您已經這樣做了)。REMOVED
:通過在userArrayList
中找到相應的項目並將其從那里刪除來處理此問題。CHANGED
:通過在userArrayList
中找到相應的項目並使用快照中的數據對其進行更新來處理此問題。 在所有這些情況下,您都需要通過調用notifyDataSetChanged
來通知適配器更改。 您可能希望在for
循環之外執行此操作,因為對於一組更改無需多次通知適配器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.