簡體   English   中英

從 Firestore 中刪除項目后 RecyclerView 不更新

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM