0

Ich arbeite an Android mit Firebase. Ich möchte eine Liste von Informationen mit einem ArrayAdapter aus einer Datenbank anzeigen. Ich benutze eine ArrayList von Uids. einige Benutzerinformationen von einer denormalized Feuerbasis Datenbank zu holen, wie so strukturiert:Anzeige von Daten aus mehreren Firebase-Datenbankreferenzen mit einem ArrayAdapter

name : { 
uid1:"bear", 
uid2:"salmon" 
}, 

phone : { 
uid1:"888-395-4023", 
uid2:"123-456-6789" 
} 

Mein aktueller Ansatz ist die abgerufenen Werte in ein Userinfo Objekt einer Klasse wie folgt zu speichern.

public UserInfo (String name, String phone) 

und fügen Sie dann jedes Objekt zum ArrayAdapter hinzu.

someArrayAdapter.add(userInfo); 

Mein Problem ist, mit mehr als einem Benutzer und Lesen von Daten von mehr als einer Referenz, in der meine folgende Umsetzung alle Felder in der zugegebenen userinfo sind leer, weil Ereignis-Listener-Rückrufe nach der Methode add() empfangen werden Anruf (Daten nicht aktualisiert wird, wenn die Rückrufe empfangen werden)

private FirebaseDatabase mFirebaseDatabase = new FirebaseDatabase.getInstance(); 
private ValueEventListener mNameListener; 
private ValueEventListener mPhoneListener; 
private DatabaseReference mNameRef; 
private DatabaseReference mPhoneRef; 

private void getUserInfo (@NonNull final ArrayList<String> uidList) 
{ 
    // This for-loop loops through the list of strings, and use the string to construct new database references. 

    for (String uid : uidList) 
    { 
      // Create a new userInfo object 
      UserInfo userInfo = new UserInfo(); 

      // Create a database reference for accessing the name 
      mNameRef = mFirebaseDatabase.getReference().child("name").child(uid); 

      // Create a database reference for accessing the name 
      mPhoneRef = mFirebaseDatabase.getReference().child("phone").child(uid); 

      // My name listener 
      mNameListener = new ValueEventListener() 
      { 
       @Override 
       public void onDataChange(final DataSnapshot dataSnapshot) { 
        String name = DataSnashot.getValue().toString(); 
        userInfo.setName(name); 
       } 
       // ...skipped irrelevant override 
      } 

      // My phone listener 
      mPhoneListener = new ValueEventListener() 
      { 
       @Override 
       public void onDataChange(final DataSnapshot dataSnapshot) { 
        String phone = DataSnashot.getValue().toString(); 
        userInfo.setPhone(phone); 

        // Log to try getting the phone from the object, as expected, is good 
        Log.i(TAG, userInfo.getPhone()); 
       } 
       // ...skipped irrelevant override 
      } 

      // Attach the listeners 
      mNameRef.addListenerForSingleValueEvent(mNameListener); 
      mPhoneRef.addListenerForSingleValueEvent(mPhoneListener); 

      // Problem here: listener callbacks are received after this method fires. 
      someArrayAdapter.add(userInfo); 

      // Log, returns empty for both fields, and this log message runs before the callback log messages above. 
      Log.i(TAG, userInfo.getName() + " " + userInfo.getPhone()); 

    } 
} 

ich haben will ein „vollständig“ userinfo Objekt vor der for-Schleife auf die nächste uid geht. Und, wie sollte ich verwalten, damit der Adapter das userInfo Objekt nur hinzufügt, wenn alle Rückrufe empfangen werden?

Ich brauche auf jeden Fall einen besseren Weg, um die Daten persistent zu machen, aber so wie es aussieht, ist es viel einfacher für die Wartung, wenn ich einfach mit einfachen Objekten umgehen kann. Vielen Dank für Ihre Hilfe und Zeit, und bitte verzeihen Sie mir für jede Syntax oder fehlende ";" Probleme, ich habe nicht den Beispielcode auf eine IDE geschrieben :)

Antwort

1

Glücklicherweise feuern die Rückrufe, aber sie sind asynchron. Das bedeutet, dass das Objekt userinfo im Hauptthread, das Sie am Anfang der for-Schleife initialisiert haben, sofort hinzugefügt wird, da Firebase auf separaten Threads ausgeführt wird.

Da die Firebase-Callbacks asynchron sind, werden sie auf ihren eigenen Threads ausgeführt und Ihre Benutzerinformationen werden sofort hinzugefügt. Da Ihre userInfo aktuell keine Informationen enthält, wird im Wesentlichen ein leeres Benutzer-Info-Objekt hinzugefügt.

Was Sie wollen, kann so erreicht werden. Sie fügen Ihr Benutzer-Info-Objekt innerhalb des Callbacks selbst hinzu.

mNameListener = new ValueEventListener() 
     { 
      @Override 
      public void onDataChange(final DataSnapshot dataSnapshot) { 
       String name = DataSnashot.getValue().toString(); 
       userInfo.setName(name) 
       // Here you make a new event listner 

       mPhoneRef.addSingleValueEventListener(new ValueEventListener(){ 

    onDataChange(DatasnapShot datasnapshot){ 
    String phone = DataSnashot.getValue().toString(); 
    userInfo.setPhone(phone); 
    someAdapater.add(userInfo); // add your user info here 
    } 

    mNameRef.addListenerForSingleValueEvent(mNameListener); 

    //someArrayAdapter.add(userInfor); // Do not have this here anymore 

Innerhalb des ersten Zuhörers können Sie einen anderen Zuhörer anschließen, um den Anruf zu erhalten. Sobald Sie den Wert haben, fügen Sie ihn zu Ihrem Adapter hinzu.

Sie sollten jedoch Ihre Datenbank neu entwerfen. Ihre Datenbank ist unglaublich ineffizient. Sie müssen keine zusätzliche Abfrage erstellen, und Sie sollten keine zusätzliche Abfrage durchführen. Sie sollten Ihre UserInfo-Objekte unter einem Knoten bündeln und sie wie gewünscht abrufen.

Ein Beispiel, wie Sie diese

durch Verwendung Push Tasten tun könnte
UserInfo userinfo = new UserInfo("Name","133405-333") 
root.child("userInfo").push().setValue(userInfo); 

Hier anstatt Ihre Informationen zu trennen, setzen sie Sie alles unter einem Knoten. Dies ist eine sehr Datenbankstruktur, da Sie bestimmte Abfragen durchführen können, ohne dass Sie einen anderen Teil Ihrer Datenbank abfragen müssen.

+0

Danke für den Kommentar, aber ich denke nicht, dass Ihr Ansatz im Maßstab funktioniert.Was die Datenbankstruktur anbelangt, befolge ich die Best Practice gemäß Firebase Docs zur Denormalisierung. Meine aktuelle Datenbank hat 14 separate Benutzerfelder. Wenn ich alle zusammen durcheinander bringe, wird die Suche nach einer passenden UID mit nur einer Information sehr lange dauern. –

+0

Angesichts der Struktur wie gezeigt, aber was ist, wenn ein Benutzer keinen Namen hat, aber eine Telefonnummer hat? Der Telefonhörer und anschließend der someAdapater werden überhaupt nicht ausgelöst –

+0

Das ist immer noch in Ordnung. Seit Firebase ist Schema weniger. Du kannst das. Userinfo userinfo = Neue UserInfo (Name). Haben Sie einfach einen Konstruktor, der nur den Namen annimmt, und Sie können diese Benutzerinformation immer noch unter den gleichen Knoten setzen –

Verwandte Themen