In diesem Dokument wird beschrieben, wie Sie mit Listen von Daten in Firebase arbeiten. Die Grundlagen zum Lesen und Schreiben von Firebase-Daten finden Sie unter Daten auf Android lesen und schreiben.
DatabaseReference abrufen
Zum Lesen und Schreiben von Daten aus der Datenbank benötigen Sie eine Instanz von DatabaseReference:
Kotlin
private lateinit var database: DatabaseReference // ... database = Firebase.database.reference
Java
private DatabaseReference mDatabase; // ... mDatabase = FirebaseDatabase.getInstance().getReference();
Listen lesen und schreiben
Daten an eine Liste anhängen
Verwenden Sie die Methode push(), um Daten an eine Liste in Mehrnutzeranwendungen anzuhängen.
Die Methode push() generiert jedes Mal einen eindeutigen Schlüssel, wenn der angegebenen Firebase-Referenz ein neues untergeordnetes Element hinzugefügt wird. Durch die Verwendung dieser automatisch generierten Schlüssel für jedes neue Element in der Liste können mehrere Clients gleichzeitig untergeordnete Elemente am selben Speicherort hinzufügen, ohne dass es zu Schreibkonflikten kommt. Der von push() generierte eindeutige Schlüssel basiert auf einem Zeitstempel, sodass Listenelemente automatisch chronologisch sortiert werden.
Sie können die von der Methode push() zurückgegebene Referenz auf die neuen Daten verwenden, um den Wert des automatisch generierten Schlüssels des untergeordneten Elements abzurufen oder Daten für das untergeordnete Element festzulegen. Wenn Sie getKey() für eine push()-Referenz aufrufen, wird der Wert des automatisch generierten Schlüssels zurückgegeben.
Sie können diese automatisch generierten Schlüssel verwenden, um die Struktur Ihrer Daten zu vereinfachen. Weitere Informationen finden Sie im Beispiel für die Datenverteilung .
Auf untergeordnete Ereignisse warten
Wenn Sie mit Listen arbeiten, sollte Ihre Anwendung auf untergeordnete Ereignisse warten und nicht auf die Wert-Ereignisse, die für einzelne Objekte verwendet werden.
Untergeordnete Ereignisse werden als Reaktion auf bestimmte Vorgänge ausgelöst, die mit den untergeordneten Elementen eines Knotens ausgeführt werden, z. B. wenn ein neues untergeordnetes Element mit der Methode push() hinzugefügt oder ein untergeordnetes Element mit der Methode updateChildren() aktualisiert wird.
Beide können zusammen nützlich sein, um auf Änderungen an einem bestimmten Knoten in einer Datenbank zu warten.
Wenn Sie auf untergeordnete Ereignisse für DatabaseReference warten möchten, fügen Sie einen ChildEventListener an:
| Listener | Ereignis-Callback | Typische Verwendung |
|---|---|---|
ChildEventListener
| onChildAdded() |
Listen von Elementen abrufen oder auf Ergänzungen zu einer Liste von Elementen warten.
Dieser Callback wird einmal für jedes vorhandene untergeordnete Element und dann wieder
jedes Mal ausgelöst, wenn dem angegebenen Pfad ein neues untergeordnetes Element hinzugefügt wird. Der DataSnapshot an den Listener übergebene enthält die die Daten des neuen untergeordneten Elements.
|
onChildChanged() |
Auf Änderungen an den Elementen in einer Liste warten. Dieses Ereignis wird jedes Mal ausgelöst, wenn ein
untergeordneter Knoten geändert wird, einschließlich aller Änderungen an untergeordneten Elementen von
untergeordneten Knoten. Der DataSnapshot an den Ereignis
Listener übergebene enthält die aktualisierten Daten für das untergeordnete Element.
|
|
onChildRemoved() |
Auf Elemente warten, die aus einer Liste entfernt werden. Der
DataSnapshot an den Ereignis-Callback übergebene enthält die
Daten für das entfernte untergeordnete Element.
|
|
onChildMoved() |
Auf Änderungen an der Reihenfolge der Elemente in einer sortierten Liste warten.
Dieses Ereignis wird ausgelöst, wenn der onChildChanged()
Callback durch eine Aktualisierung ausgelöst wird, die eine Neusortierung des untergeordneten Elements verursacht.
Es wird mit Daten verwendet, die mit orderByChild oder orderByValue sortiert sind.
|
In einer Social-Blogging-App können diese Methoden beispielsweise zusammen verwendet werden, um die Aktivität in den Kommentaren eines Beitrags zu beobachten, wie unten gezeigt:
Kotlin
val childEventListener = object : ChildEventListener { override fun onChildAdded(dataSnapshot: DataSnapshot, previousChildName: String?) { Log.d(TAG, "onChildAdded:" + dataSnapshot.key!!) // A new comment has been added, add it to the displayed list val comment = dataSnapshot.getValue<Comment>() // ... } override fun onChildChanged(dataSnapshot: DataSnapshot, previousChildName: String?) { Log.d(TAG, "onChildChanged: ${dataSnapshot.key}") // A comment has changed, use the key to determine if we are displaying this // comment and if so displayed the changed comment. val newComment = dataSnapshot.getValue<Comment>() val commentKey = dataSnapshot.key // ... } override fun onChildRemoved(dataSnapshot: DataSnapshot) { Log.d(TAG, "onChildRemoved:" + dataSnapshot.key!!) // A comment has changed, use the key to determine if we are displaying this // comment and if so remove it. val commentKey = dataSnapshot.key // ... } override fun onChildMoved(dataSnapshot: DataSnapshot, previousChildName: String?) { Log.d(TAG, "onChildMoved:" + dataSnapshot.key!!) // A comment has changed position, use the key to determine if we are // displaying this comment and if so move it. val movedComment = dataSnapshot.getValue<Comment>() val commentKey = dataSnapshot.key // ... } override fun onCancelled(databaseError: DatabaseError) { Log.w(TAG, "postComments:onCancelled", databaseError.toException()) Toast.makeText( context, "Failed to load comments.", Toast.LENGTH_SHORT, ).show() } } databaseReference.addChildEventListener(childEventListener)
Java
ChildEventListener childEventListener = new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey()); // A new comment has been added, add it to the displayed list Comment comment = dataSnapshot.getValue(Comment.class); // ... } @Override public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) { Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey()); // A comment has changed, use the key to determine if we are displaying this // comment and if so displayed the changed comment. Comment newComment = dataSnapshot.getValue(Comment.class); String commentKey = dataSnapshot.getKey(); // ... } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey()); // A comment has changed, use the key to determine if we are displaying this // comment and if so remove it. String commentKey = dataSnapshot.getKey(); // ... } @Override public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) { Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey()); // A comment has changed position, use the key to determine if we are // displaying this comment and if so move it. Comment movedComment = dataSnapshot.getValue(Comment.class); String commentKey = dataSnapshot.getKey(); // ... } @Override public void onCancelled(DatabaseError databaseError) { Log.w(TAG, "postComments:onCancelled", databaseError.toException()); Toast.makeText(mContext, "Failed to load comments.", Toast.LENGTH_SHORT).show(); } }; databaseReference.addChildEventListener(childEventListener);
Auf Wert-Ereignisse warten
Die Verwendung eines ChildEventListener ist zwar die empfohlene Methode zum Lesen von Datenlisten, es gibt jedoch Situationen, in denen es nützlich ist, einen ValueEventListener an eine Listenreferenz anzuhängen.
Wenn Sie einen ValueEventListener an eine Datenliste anhängen, wird die gesamte Datenliste als einzelner DataSnapshot zurückgegeben, den Sie dann durchlaufen können, um auf einzelne untergeordnete Elemente zuzugreifen.
Auch wenn es nur eine Übereinstimmung für die Abfrage gibt, ist der Snapshot weiterhin eine Liste, die nur ein einzelnes Element enthält. Um auf das Element zuzugreifen, müssen Sie das Ergebnis durchlaufen:
Kotlin
// My top posts by number of stars myTopPostsQuery.addValueEventListener(object : ValueEventListener { override fun onDataChange(dataSnapshot: DataSnapshot) { for (postSnapshot in dataSnapshot.children) { // TODO: handle the post } } override fun onCancelled(databaseError: DatabaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()) // ... } })
Java
// My top posts by number of stars myTopPostsQuery.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) { // TODO: handle the post } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()); // ... } });
Dieses Muster kann nützlich sein, wenn Sie alle untergeordneten Elemente einer Liste in einem einzigen Vorgang abrufen möchten, anstatt auf zusätzliche onChildAdded-Ereignisse zu warten.
Listener trennen
Callbacks werden entfernt, indem Sie die Methode removeEventListener() für Ihre Firebase-Datenbankreferenz aufrufen.
Wenn ein Listener mehrmals zu einem Datenspeicherort hinzugefügt wurde, wird er für jedes Ereignis mehrmals aufgerufen. Sie müssen ihn genauso oft trennen, um ihn vollständig zu entfernen.
Wenn Sie removeEventListener() für einen übergeordneten Listener aufrufen, werden Listener, die für die untergeordneten Knoten registriert sind, nicht automatisch entfernt. removeEventListener() muss auch für alle untergeordneten Listener aufgerufen werden, um den Callback zu entfernen.
Daten sortieren und filtern
Mit der Klasse Realtime Database Query können Sie Daten abrufen, die nach
Schlüssel, Wert oder Wert eines untergeordneten Elements sortiert sind. Sie können das sortierte Ergebnis auch auf eine bestimmte Anzahl von Ergebnissen oder einen Bereich von Schlüsseln oder Werten filtern.
Daten sortieren
Wenn Sie sortierte Daten abrufen möchten, geben Sie zuerst eine der Sortiermethoden an, um zu bestimmen, wie die Ergebnisse sortiert werden:
| Methode | Nutzung |
|---|---|
orderByChild() |
Ergebnisse nach dem Wert eines angegebenen untergeordneten Schlüssels oder eines verschachtelten untergeordneten Pfads sortieren. |
orderByKey()
| Ergebnisse nach untergeordneten Schlüsseln sortieren. |
orderByValue() |
Ergebnisse nach untergeordneten Werten sortieren. |
Sie können jeweils nur eine Sortiermethode verwenden. Wenn Sie in derselben Abfrage mehrmals eine Sortiermethode aufrufen, wird ein Fehler ausgelöst.
Im folgenden Beispiel wird gezeigt, wie Sie eine Liste der Top-Beiträge eines Nutzers abrufen können, sortiert nach der Anzahl der Sterne:
Kotlin
// My top posts by number of stars val myUserId = uid val myTopPostsQuery = databaseReference.child("user-posts").child(myUserId) .orderByChild("starCount") myTopPostsQuery.addChildEventListener(object : ChildEventListener { // TODO: implement the ChildEventListener methods as documented above // ... })
Java
// My top posts by number of stars String myUserId = getUid(); Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId) .orderByChild("starCount"); myTopPostsQuery.addChildEventListener(new ChildEventListener() { // TODO: implement the ChildEventListener methods as documented above // ... });
Dadurch wird eine Abfrage definiert, die in Kombination mit einem Listener für untergeordnete Elemente den Client mit den Beiträgen des Nutzers aus dem Pfad in der Datenbank synchronisiert basierend auf der Nutzer-ID und sortiert nach der Anzahl der Sterne, die jeder Beitrag erhalten hat. Diese Technik, IDs als Indexschlüssel zu verwenden, wird als Datenverteilung bezeichnet. Weitere Informationen finden Sie unter Datenbank strukturieren.
Der Aufruf der Methode orderByChild() gibt den untergeordneten Schlüssel an, nach dem die Ergebnisse sortiert werden sollen. In diesem Fall werden die Beiträge nach dem Wert des jeweiligen untergeordneten Elements
"starCount" sortiert. Abfragen können auch nach verschachtelten untergeordneten Elementen sortiert werden, falls Ihre Daten so aussehen:
"posts": {
"ts-functions": {
"metrics": {
"views" : 1200000,
"likes" : 251000,
"shares": 1200,
},
"title" : "Why you should use TypeScript for writing Cloud Functions",
"author": "Doug",
},
"android-arch-3": {
"metrics": {
"views" : 900000,
"likes" : 117000,
"shares": 144,
},
"title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
"author": "Doug",
}
},In diesem Beispiel können wir unsere Listenelemente nach Werten sortieren, die unter dem Schlüssel metrics verschachtelt sind, indem wir den relativen Pfad zum verschachtelten untergeordneten Element in unserem orderByChild()-Aufruf angeben.
Kotlin
// Most viewed posts val myMostViewedPostsQuery = databaseReference.child("posts") .orderByChild("metrics/views") myMostViewedPostsQuery.addChildEventListener(object : ChildEventListener { // TODO: implement the ChildEventListener methods as documented above // ... })
Java
// Most viewed posts Query myMostViewedPostsQuery = databaseReference.child("posts") .orderByChild("metrics/views"); myMostViewedPostsQuery.addChildEventListener(new ChildEventListener() { // TODO: implement the ChildEventListener methods as documented above // ... });
Weitere Informationen zur Sortierung anderer Datentypen finden Sie unter So werden Abfragedaten sortiert.
Daten filtern
Zum Filtern von Daten können Sie beim Erstellen einer Abfrage eine der Methoden für Limit oder Bereich mit einer Sortiermethode kombinieren.
| Methode | Nutzung |
|---|---|
limitToFirst() |
Legt die maximale Anzahl der Elemente fest, die vom Anfang der sortierten Ergebnisliste zurückgegeben werden sollen. |
limitToLast() |
Legt die maximale Anzahl der Elemente fest, die vom Ende der sortierten Ergebnisliste zurückgegeben werden sollen. |
startAt() |
Gibt Elemente zurück, die größer oder gleich dem angegebenen Schlüssel oder Wert sind je nach gewählter Sortiermethode. |
startAfter() |
Gibt Elemente zurück, die größer als der angegebene Schlüssel oder Wert sind je nach gewählter Sortiermethode. |
endAt() |
Gibt Elemente zurück, die kleiner oder gleich dem angegebenen Schlüssel oder Wert sind je nach gewählter Sortiermethode. |
endBefore() |
Gibt Elemente zurück, die kleiner als der angegebene Schlüssel oder Wert sind je nach gewählter Sortiermethode. |
equalTo() |
Gibt Elemente zurück, die gleich dem angegebenen Schlüssel oder Wert sind je nach gewählter Sortiermethode. |
Im Gegensatz zu den Sortiermethoden können Sie mehrere Limit- oder Bereichsfunktionen kombinieren.
Sie können beispielsweise die Methoden startAt() und endAt() kombinieren, um die Ergebnisse auf einen bestimmten Wertebereich zu beschränken.
Auch wenn es nur eine Übereinstimmung für die Abfrage gibt, ist der Snapshot weiterhin eine Liste, die nur ein einzelnes Element enthält. Um auf das Element zuzugreifen, müssen Sie das Ergebnis durchlaufen:
Kotlin
// My top posts by number of stars myTopPostsQuery.addValueEventListener(object : ValueEventListener { override fun onDataChange(dataSnapshot: DataSnapshot) { for (postSnapshot in dataSnapshot.children) { // TODO: handle the post } } override fun onCancelled(databaseError: DatabaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()) // ... } })
Java
// My top posts by number of stars myTopPostsQuery.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) { // TODO: handle the post } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()); // ... } });
Anzahl der Ergebnisse begrenzen
Mit den Methoden limitToFirst() und limitToLast() können Sie eine maximale Anzahl von untergeordneten Elementen festlegen, die für einen bestimmten Callback synchronisiert werden sollen. Wenn Sie beispielsweise mit limitToFirst() ein Limit von 100 festlegen, erhalten Sie zunächst nur bis zu 100 onChildAdded()-Callbacks. Wenn in Ihrer Firebase-Datenbank weniger als 100 Elemente gespeichert sind, wird für jedes Element ein onChildAdded()-Callback ausgelöst.
Wenn sich Elemente ändern, erhalten Sie onChildAdded()-Callbacks für Elemente, die in die Abfrage aufgenommen werden, und onChildRemoved()-Callbacks für Elemente, die aus der Abfrage entfernt werden, sodass die Gesamtzahl bei 100 bleibt.
Im folgenden Beispiel wird gezeigt, wie in einer Blogging-Beispiel-App eine Abfrage definiert wird, um eine Liste der 100 neuesten Beiträge aller Nutzer abzurufen:
Kotlin
// Last 100 posts, these are automatically the 100 most recent // due to sorting by push() keys. databaseReference.child("posts").limitToFirst(100)
Java
// Last 100 posts, these are automatically the 100 most recent // due to sorting by push() keys Query recentPostsQuery = databaseReference.child("posts") .limitToFirst(100);
In diesem Beispiel wird nur eine Abfrage definiert. Um Daten tatsächlich zu synchronisieren, muss ein angehängter Listener vorhanden sein.
Nach Schlüssel oder Wert filtern
Mit startAt(), startAfter(), endAt(), endBefore() und equalTo() können Sie beliebige Start-, End- und Äquivalenzpunkte für Abfragen auswählen. Dies kann nützlich sein, um Daten zu paginieren oder Elemente mit untergeordneten Elementen zu finden, die einen bestimmten Wert haben.
So werden Abfragedaten sortiert
In diesem Abschnitt wird erläutert, wie Daten mit den einzelnen Sortiermethoden in der Klasse Query sortiert werden.
orderByChild
Bei Verwendung von orderByChild() werden Daten, die den angegebenen untergeordneten Schlüssel enthalten, wie folgt sortiert:
- Untergeordnete Elemente mit einem
nullWert für den angegebenen untergeordneten Schlüssel werden zuerst angezeigt. - Untergeordnete Elemente mit dem Wert
falsefür den angegebenen untergeordneten Schlüssel werden als Nächstes angezeigt. Wenn mehrere untergeordnete Elemente den Wertfalsehaben, werden sie lexikografischsortiert nach Schlüssel. - Untergeordnete Elemente mit dem Wert
truefür den angegebenen untergeordneten Schlüssel werden als Nächstes angezeigt. Wenn mehrere untergeordnete Elemente den Werttruehaben, werden sie lexikografisch nach Schlüssel sortiert. - Untergeordnete Elemente mit einem numerischen Wert werden als Nächstes angezeigt, sortiert in aufsteigender Reihenfolge. Wenn mehrere untergeordnete Elemente denselben numerischen Wert für den angegebenen untergeordneten Knoten haben, werden sie nach Schlüssel sortiert.
- Strings folgen auf Zahlen und werden lexikografisch in aufsteigender Ordnung sortiert. Wenn mehrere untergeordnete Elemente denselben Wert für den angegebenen untergeordneten Knoten haben, werden sie lexikografisch nach Schlüssel sortiert.
- Objekte werden zuletzt angezeigt und lexikografisch nach Schlüssel in aufsteigender Reihenfolge sortiert.
orderByKey
Wenn Sie orderByKey() zum Sortieren Ihrer Daten verwenden, werden die Daten in aufsteigender Reihenfolge nach Schlüssel zurückgegeben.
- Untergeordnete Elemente mit einem Schlüssel, der als 32-Bit-Ganzzahl geparst werden kann, werden zuerst angezeigt, sortiert in aufsteigender Reihenfolge.
- Untergeordnete Elemente mit einem Stringwert als Schlüssel werden als Nächstes angezeigt, sortiert lexikografisch in aufsteigender Reihenfolge.
orderByValue
Bei Verwendung von orderByValue() werden untergeordnete Elemente nach ihrem Wert sortiert. Die Sortierkriterien sind dieselben wie bei orderByChild(), außer dass der Wert des Knotens anstelle des Werts eines angegebenen untergeordneten Schlüssels verwendet wird.