Dieses Dokument behandelt die Arbeit mit Datenlisten in Firebase. Informationen zu den Grundlagen des Lesens und Schreibens von Firebase-Daten finden Sie unter Lesen und Schreiben von Daten auf Android .
Holen Sie sich eine Datenbankreferenz
Um Daten aus der Datenbank zu lesen und zu schreiben, benötigen Sie eine Instanz von DatabaseReference
:
Kotlin+KTX
private lateinit var database: DatabaseReference // ... database = Firebase.database.reference
Java
private DatabaseReference mDatabase; // ... mDatabase = FirebaseDatabase.getInstance().getReference();
Listen lesen und schreiben
An eine Datenliste anhängen
Verwenden Sie die Methode push()
, um Daten in Mehrbenutzeranwendungen an eine Liste 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 Kinder an derselben Stelle hinzufügen, ohne dass es zu Schreibkonflikten kommt. Der von push()
generierte eindeutige Schlüssel basiert auf einem Zeitstempel, sodass Listenelemente automatisch chronologisch geordnet werden.
Sie können den Verweis auf die neuen Daten verwenden, die von der push()
Methode zurückgegeben werden, um den Wert des automatisch generierten Schlüssels des untergeordneten Elements abzurufen oder Daten für das untergeordnete Element festzulegen. Der Aufruf von getKey()
für eine push()
Referenz gibt den Wert des automatisch generierten Schlüssels zurück.
Sie können diese automatisch generierten Schlüssel verwenden, um das Vereinfachen Ihrer Datenstruktur zu vereinfachen. Weitere Informationen finden Sie im Datenauffächerungsbeispiel .
Achten Sie auf untergeordnete Ereignisse
Wenn Sie mit Listen arbeiten, sollte Ihre Anwendung auf untergeordnete Ereignisse lauschen und nicht auf Wertereignisse, die für einzelne Objekte verwendet werden.
Untergeordnete Ereignisse werden als Reaktion auf bestimmte Operationen ausgelöst, die mit den untergeordneten Knoten eines Knotens von einer Operation ausgeführt werden, wie z. B. ein neues untergeordnetes Element, das durch die push()
Methode hinzugefügt wird, oder ein untergeordnetes Element, das durch die updateChildren()
Methode aktualisiert wird. Alle zusammen können nützlich sein, um Änderungen an einem bestimmten Knoten in einer Datenbank abzuhören.
Um nach untergeordneten Ereignissen auf DatabaseReference
zu lauschen, hängen Sie einen ChildEventListener
an:
Hörer | Ereignisrückruf | Typische Verwendung |
---|---|---|
ChildEventListener | onChildAdded() | Rufen Sie Listen von Elementen ab oder hören Sie auf Ergänzungen zu einer Liste von Elementen. Dieser Rückruf wird einmal für jedes vorhandene untergeordnete Element ausgelöst und dann erneut jedes Mal, wenn dem angegebenen Pfad ein neues untergeordnetes Element hinzugefügt wird. Der an den Listener übergebene DataSnapshot enthält die Daten des neuen Kindes. |
onChildChanged() | Überwachen Sie Änderungen an den Elementen in einer Liste. Dieses Ereignis wird jedes Mal ausgelöst, wenn ein untergeordneter Knoten geändert wird, einschließlich aller Änderungen an Nachkommen des untergeordneten Knotens. Der an den Ereignis-Listener übergebene DataSnapshot enthält die aktualisierten Daten für das untergeordnete Element. | |
onChildRemoved() | Listen Sie auf Elemente, die aus einer Liste entfernt werden. Der an den Ereignisrückruf übergebene DataSnapshot enthält die Daten für das entfernte Kind. | |
onChildMoved() | Überwachen Sie Änderungen an der Reihenfolge der Elemente in einer geordneten Liste. Dieses Ereignis wird immer dann ausgelöst, wenn der onChildChanged() Callback durch eine Aktualisierung ausgelöst wird, die eine Neuordnung des untergeordneten Elements verursacht. Es wird mit Daten verwendet, die mit orderByChild oder orderByValue bestellt werden. |
Beispielsweise könnte eine Social-Blogging-App diese Methoden zusammen verwenden, um die Aktivität in den Kommentaren eines Beitrags zu überwachen, wie unten gezeigt:
Kotlin+KTX
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);
Achten Sie auf Wertereignisse
Während die Verwendung eines ChildEventListener
die empfohlene Methode zum Lesen von Datenlisten ist, gibt es Situationen, in denen das Anhängen eines ValueEventListener
an eine Listenreferenz nützlich ist.
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.
Selbst wenn es nur eine einzige Übereinstimmung für die Abfrage gibt, ist der Schnappschuss immer noch eine Liste; es enthält nur ein einzelnes Element. Um auf das Element zuzugreifen, müssen Sie das Ergebnis durchlaufen:
Kotlin+KTX
// 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.
Zuhörer trennen
Rückrufe werden entfernt, indem die Methode removeEventListener()
für Ihre Firebase-Datenbankreferenz aufgerufen wird.
Wenn ein Listener mehrmals zu einem Datenspeicherort hinzugefügt wurde, wird er für jedes Ereignis mehrmals aufgerufen, und Sie müssen ihn genauso oft trennen, um ihn vollständig zu entfernen.
Das Aufrufen von removeEventListener()
für einen übergeordneten Listener entfernt nicht automatisch Listener, die auf seinen untergeordneten Knoten registriert sind; removeEventListener()
muss auch für alle untergeordneten Listener aufgerufen werden, um den Rückruf zu entfernen.
Daten sortieren und filtern
Sie können die Realtime Database Query
-Klasse verwenden, um Daten abzurufen, die nach Schlüssel, nach Wert oder nach Wert eines untergeordneten Elements sortiert sind. Sie können das sortierte Ergebnis auch nach einer bestimmten Anzahl von Ergebnissen oder einem Bereich von Schlüsseln oder Werten filtern.
Daten sortieren
Um sortierte Daten abzurufen, geben Sie zunächst eine der Sortiermethoden an, um zu bestimmen, wie die Ergebnisse sortiert werden:
Methode | Verwendung |
---|---|
orderByChild() | Sortieren Sie die Ergebnisse nach dem Wert eines angegebenen untergeordneten Schlüssels oder verschachtelten untergeordneten Pfads. | orderByKey() | Sortieren Sie die Ergebnisse nach untergeordneten Schlüsseln. |
orderByValue() | Sortieren Sie die Ergebnisse nach untergeordneten Werten. |
Sie können jeweils nur eine Order-by-Methode verwenden. Das mehrmalige Aufrufen einer Order-By-Methode in derselben Abfrage löst einen Fehler aus.
Das folgende Beispiel zeigt, wie Sie eine Liste der Top-Beiträge eines Benutzers abrufen können, sortiert nach der Anzahl der Sterne:
Kotlin+KTX
// 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 // ... });
Dies definiert eine Abfrage, die in Kombination mit einem untergeordneten Listener den Client mit den Posts des Benutzers aus dem Pfad in der Datenbank basierend auf seiner Benutzer-ID synchronisiert, sortiert nach der Anzahl der Sterne, die jeder Post erhalten hat. Diese Technik der Verwendung von IDs als Indexschlüssel wird als Datenauffächerung bezeichnet. Sie können mehr darüber in Structure Your Database lesen.
Der Aufruf der Methode orderByChild()
gibt den untergeordneten Schlüssel an, nach dem die Ergebnisse sortiert werden sollen. In diesem Fall werden Beiträge nach dem Wert ihres jeweiligen "starCount"
-Kindes sortiert. Abfragen können auch nach verschachtelten untergeordneten Elementen geordnet werden, falls Sie Daten haben, die wie folgt 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 metrics
verschachtelt sind, indem wir den relativen Pfad zum verschachtelten untergeordneten Element in unserem Aufruf orderByChild()
angeben.
Kotlin+KTX
// 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 Sortierung von Abfragedaten .
Filtern von Daten
Um Daten zu filtern, können Sie beim Erstellen einer Abfrage jede der Limit- oder Range-Methoden mit einer Order-By-Methode kombinieren.
Methode | Verwendung |
---|---|
limitToFirst() | Legt die maximale Anzahl von Elementen fest, die vom Anfang der geordneten Ergebnisliste zurückgegeben werden. |
limitToLast() | Legt die maximale Anzahl von Elementen fest, die vom Ende der geordneten Ergebnisliste zurückgegeben werden. |
startAt() | Gibt je nach gewählter Sortiermethode Elemente zurück, die größer oder gleich dem angegebenen Schlüssel oder Wert sind. |
startAfter() | Gibt je nach gewählter Sortiermethode Elemente zurück, die größer als der angegebene Schlüssel oder Wert sind. |
endAt() | Gibt je nach gewählter Sortiermethode Elemente zurück, die kleiner oder gleich dem angegebenen Schlüssel oder Wert sind. |
endBefore() | Gibt je nach gewählter Sortiermethode Elemente zurück, die kleiner als der angegebene Schlüssel oder Wert sind. |
equalTo() | Gibt je nach gewählter Sortiermethode Elemente zurück, die dem angegebenen Schlüssel oder Wert entsprechen. |
Im Gegensatz zu den Order-by-Methoden können Sie mehrere Limit- oder Bereichsfunktionen kombinieren. Beispielsweise können Sie die Methoden startAt()
und endAt()
kombinieren, um die Ergebnisse auf einen bestimmten Wertebereich zu beschränken.
Selbst wenn es nur eine einzige Übereinstimmung für die Abfrage gibt, ist der Schnappschuss immer noch eine Liste; es enthält nur ein einzelnes Element. Um auf das Element zuzugreifen, müssen Sie das Ergebnis durchlaufen:
Kotlin+KTX
// 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()); // ... } });
Begrenzen Sie die Anzahl der Ergebnisse
Sie können die Methoden limitToFirst()
und limitToLast()
verwenden, um eine maximale Anzahl untergeordneter Elemente festzulegen, die für einen bestimmten Rückruf synchronisiert werden sollen. Wenn Sie beispielsweise mit limitToFirst()
ein Limit von 100 festlegen, erhalten Sie zunächst nur bis zu 100 onChildAdded()
Callbacks. Wenn Sie weniger als 100 Elemente in Ihrer Firebase-Datenbank gespeichert haben, 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 daraus herausfallen, sodass die Gesamtzahl bei 100 bleibt.
Das folgende Beispiel zeigt, wie die Beispiel-Blogging-App eine Abfrage definiert, um eine Liste der 100 neuesten Posts aller Benutzer abzurufen:
Kotlin+KTX
// 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);
Dieses Beispiel definiert nur eine Abfrage, um Daten tatsächlich zu synchronisieren, muss sie einen angehängten Listener haben.
Filtern Sie nach Schlüssel oder Wert
Sie können startAt()
, startAfter()
, endAt()
, endBefore()
und equalTo()
verwenden, um beliebige Start-, End- und Äquivalenzpunkte für Abfragen auszuwählen. Dies kann nützlich sein, um Daten zu paginieren oder Elemente mit untergeordneten Elementen zu finden, die einen bestimmten Wert haben.
Wie Abfragedaten geordnet werden
In diesem Abschnitt wird erläutert, wie Daten von den einzelnen Sortiermethoden in der Query
Klasse sortiert werden.
orderByChild
Bei der Verwendung von orderByChild()
werden Daten, die den angegebenen untergeordneten Schlüssel enthalten, wie folgt geordnet:
- Kinder mit einem
null
für den angegebenen untergeordneten Schlüssel kommen zuerst. - Als nächstes kommen Kinder mit dem Wert
false
für den angegebenen untergeordneten Schlüssel. Wenn mehrere Kinder den Wertfalse
haben, werden sie lexikografisch nach Schlüssel sortiert. - Als nächstes kommen Kinder mit dem Wert
true
für den angegebenen untergeordneten Schlüssel. Wenn mehrere Kinder den Werttrue
haben, werden sie lexikografisch nach Schlüssel sortiert. - Kinder mit einem numerischen Wert kommen als nächstes, in aufsteigender Reihenfolge sortiert. Wenn mehrere untergeordnete Knoten denselben numerischen Wert für den angegebenen untergeordneten Knoten haben, werden sie nach Schlüssel sortiert.
- Zeichenfolgen kommen nach Zahlen und werden lexikographisch in aufsteigender Reihenfolge sortiert. Wenn mehrere untergeordnete Knoten denselben Wert für den angegebenen untergeordneten Knoten haben, werden sie lexikografisch nach Schlüssel geordnet.
- Die Objekte kommen zuletzt und werden lexikografisch nach Schlüsseln in aufsteigender Reihenfolge sortiert.
orderByKey
Wenn Sie orderByKey()
zum Sortieren Ihrer Daten verwenden, werden die Daten in aufsteigender Reihenfolge nach Schlüssel zurückgegeben.
- Kinder mit einem Schlüssel, der als 32-Bit-Ganzzahl geparst werden kann, kommen zuerst, sortiert in aufsteigender Reihenfolge.
- Kinder mit einem Zeichenfolgenwert als Schlüssel kommen als nächstes, lexikografisch in aufsteigender Reihenfolge sortiert.
orderByValue
Bei der Verwendung von orderByValue()
werden Kinder nach ihrem Wert geordnet. Die Sortierkriterien sind dieselben wie in orderByChild()
, außer dass der Wert des Knotens anstelle des Werts eines angegebenen untergeordneten Schlüssels verwendet wird.