Suche…


Bemerkungen

Andere verwandte Themen:

Firebase Realtime DataBase-Ereignishandler

Initialisieren Sie zuerst FirebaseDatabase:

FirebaseDatabase database = FirebaseDatabase.getInstance();

Schreiben Sie in Ihre Datenbank:

// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");

myRef.setValue("Hello, World!");

Lesen Sie aus Ihrer Datenbank:

// Read from the database
myRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // This method is called once with the initial value and again
        // whenever data at this location is updated.
        String value = dataSnapshot.getValue(String.class);
        Log.d(TAG, "Value is: " + value);
    }

    @Override
    public void onCancelled(DatabaseError error) {
        // Failed to read value
        Log.w(TAG, "Failed to read value.", error.toException());
    }
});

Daten zu Android-Ereignissen abrufen:

ChildEventListener childEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());

    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildMoved:" + 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();
    }
};
ref.addChildEventListener(childEventListener);

Schnelle Einrichtung

  1. Schließen Sie den Installations- und Setup-Teil ab , um Ihre App mit Firebase zu verbinden.
    Dadurch wird das Projekt in Firebase erstellt.

  2. Fügen Sie der build.gradle Datei auf Modulebene die Abhängigkeit für die Firebase-Echtzeitdatenbank build.gradle :

compile 'com.google.firebase:firebase-database:10.2.1'
  1. Konfigurieren Sie die Firebase-Datenbankregeln

Jetzt können Sie mit der Echtzeitdatenbank in Android arbeiten.

Beispielsweise schreiben Sie eine Hello World Nachricht unter dem message in die Datenbank.

// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");

myRef.setValue("Hello, World!");

Entwerfen und Verstehen, wie Echtzeitdaten aus der Firebase-Datenbank abgerufen werden

In diesem Beispiel wird davon ausgegangen, dass Sie bereits eine Firebase-Echtzeitdatenbank eingerichtet haben. Wenn Sie ein Anfänger sind, informieren Sie sich hier, wie Sie Firebase zu Ihrem Android-Projekt hinzufügen.

Fügen Sie zunächst die Abhängigkeit der Firebase-Datenbank zur Datei build.gradle auf App-Ebene hinzu :

compile 'com.google.firebase:firebase-database:9.4.0'

Lassen Sie uns nun eine Chat-App erstellen, die Daten in der Firebase-Datenbank speichert.

Schritt 1: Erstellen Sie eine Klasse mit dem Namen Chat

Erstellen Sie einfach eine Klasse mit einigen grundlegenden Variablen, die für den Chat erforderlich sind:

public class Chat{
    public String name, message;
}

Schritt 2: Erstellen Sie einige JSON-Daten

Um Daten an die Firebase-Datenbank zu senden / abzurufen, müssen Sie JSON verwenden. Nehmen wir an, dass einige Chats bereits auf Stammebene in der Datenbank gespeichert sind. Die Daten dieser Chats könnten wie folgt aussehen:

[
    {
        "name":"John Doe",
        "message":"My first Message"
    },
    {
        "name":"John Doe",
        "message":"Second Message"
    },
    {
        "name":"John Doe",
        "message":"Third Message"
    }
]

Schritt 3: Hinzufügen der Hörer

Es gibt drei Arten von Zuhörern. Im folgenden Beispiel verwenden wir den childEventListener :

DatabaseReference chatDb = FirebaseDatabase.getInstance().getReference() // Referencing the root of the database.
        .child("chats"); // Referencing the "chats" node under the root.

chatDb.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {
        // This function is called for every child id chat in this case, so using the above
        // example, this function is going to be called 3 times.
        
        // Retrieving the Chat object from this function is simple.
        Chat chat; // Create a null chat object.

        // Use the getValue function in the dataSnapshot and pass the object's class name to
        // which you want to convert and get data. In this case it is Chat.class.
        chat = dataSnapshot.getValue(Chat.class);

        // Now you can use this chat object and add it into an ArrayList or something like
        // that and show it in the recycler view.
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String s) {
        // This function is called when any of the node value is changed, dataSnapshot will
        // get the data with the key of the child, so you can swap the new value with the
        // old one in the ArrayList or something like that.

        // To get the key, use the .getKey() function.
        // To get the value, use code similar to the above one.
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
        // This function is called when any of the child node is removed. dataSnapshot will
        // get the data with the key of the child.

        // To get the key, use the s String parameter .
    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String s) {
        // This function is called when any of the child nodes is moved to a different position.

        // To get the key, use the s String parameter.
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // If anything goes wrong, this function is going to be called.

        // You can get the exception by using databaseError.toException();
    }
});

Schritt 4: Fügen Sie Daten zur Datenbank hinzu

Erstellen Sie einfach ein Chat-Klassenobjekt und fügen Sie die Werte wie folgt hinzu:

Chat chat=new Chat();
chat.name="John Doe";
chat.message="First message from android";

Rufen Sie nun wie in der Abrufsitzung einen Verweis auf den Chats-Knoten ab:

DatabaseReference chatDb = FirebaseDatabase.getInstance().getReference().child("chats");

Bevor Sie mit dem Hinzufügen von Daten beginnen, bedenken Sie, dass Sie eine weitere ausführliche Referenz benötigen, da ein Chat-Knoten mehrere weitere Knoten hat. Wenn Sie einen neuen Chat hinzufügen, müssen Sie einen neuen Knoten hinzufügen, der die Chat-Details enthält. Wir können einen neuen und eindeutigen Namen des Knotens mit der Funktion push() für das DatabaseReference Objekt generieren, das eine andere DatabaseReference , die wiederum auf einen neu gebildeten Knoten verweist, um die Chat-Daten einzufügen.

Beispiel

// The parameter is the chat object that was newly created a few lines above.
chatDb.push().setValue(chat);

Die setValue() Funktion stellt sicher, dass alle onDataChanged Funktionen der Anwendung aufgerufen werden (einschließlich des gleichen Geräts). onDataChanged ist der angehängte Listener des Chats "chats".

Denormalisierung: Flache Datenbankstruktur

Denormalisierung und eine flache Datenbankstruktur sind erforderlich, um separate Aufrufe effizient herunterzuladen. Mit der folgenden Struktur können auch wechselseitige Beziehungen aufrechterhalten werden. Der Nachteil dieses Ansatzes ist, dass Sie die Daten immer an mehreren Stellen aktualisieren müssen.

Stellen Sie sich zum Beispiel eine App vor, mit der der Benutzer Nachrichten für sich selbst speichern kann (Memos).

Gewünschte flache Datenbankstruktur:

|--database
  |-- memos
     |-- memokey1
       |-- title: "Title"
       |-- content: "Message"
     |-- memokey2
       |-- title: "Important Title"
       |-- content: "Important Message"
  |-- users
     |-- userKey1
       |-- name: "John Doe"
       |-- memos
         |-- memokey1 : true //The values here don't matter, we only need the keys.
         |-- memokey2 : true
     |-- userKey2
       |-- name: "Max Doe"

Die verwendete Memo-Klasse

public class Memo {
    private String title, content;
    //getters and setters ... 

    //toMap() is necessary for the push process
    private Map<String, Object> toMap() {
        HashMap<String, Object> result = new HashMap<>();
        result.put("title", title);
        result.put("content", content);
        return result;
    }
}

Abrufen der Memos eines Benutzers

//We need to store the keys and the memos seperately
private ArrayList<String> mKeys = new ArrayList<>();
private ArrayList<Memo> mMemos = new ArrayList<>();

//The user needs to be logged in to retrieve the uid
String currentUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();

//This is the reference to the list of memos a user has 
DatabaseReference currentUserMemoReference = FirebaseDatabase.getInstance().getReference()
    .child("users").child(currentUserId).child("memos");

//This is a reference to the list of all memos
DatabaseReference memoReference = FirebaseDatabase.getInstance().getReference()
    .child("memos");

//We start to listen to the users memos, 
//this will also retrieve the memos initially
currentUserMemoReference.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s) {
            //Here we retrieve the key of the memo the user has.
            String key = dataSnapshot.getKey(); //for example memokey1
            //For later manipulations of the lists, we need to store the key in a list
            mKeys.add(key);
            //Now that we know which message belongs to the user, 
            //we request it from our memos:
            memoReference.child(key).addValueEventListener(new ValueEventListener() {
                @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                         //Here we retrieve our memo:
                         Memo memo = dataSnapshot.getValue(Memo.class);
                         mMemos.add(memo);
                    }

                @Override
                public void onCancelled(DatabaseError databaseError) { }
            });                           
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) { }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) { }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String s) { }

        @Override
        public void onCancelled(DatabaseError databaseError) { }
    }

Memo erstellen

//The user needs to be logged in to retrieve the uid
String currentUserUid = FirebaseAuth.getInstance().getCurrentUser().getUid();

//This is the path to the list of memos a user has 
String userMemoPath = "users/" + currentUserUid + "/memos/";

//This is the path to the list of all memos
String memoPath = "memos/";

//We need to retrieve an unused key from the memos reference
DatabaseReference memoReference = FirebaseDatabase.getInstance().getReference().child("memos");
String key = memoReference.push().getKey();
Memo newMemo = new Memo("Important numbers", "1337, 42, 3.14159265359");

Map<String, Object> childUpdates = new HashMap<>(); 
//The second parameter **here** (the value) does not matter, it's just that the key exists
childUpdates.put(userMemoPath + key, true);
childUpdates.put(memoPath + key, newMemo.toMap());

FirebaseDatabase.getInstance().getReference().updateChildren(childUpdates);

Nach dem Push oder der Datenbank sieht das so aus:

|--database
  |-- memos
     |-- memokey1
       |-- title: "Title"
       |-- content: "Message"
     |-- memokey2
       |-- title: "Important Title"
       |-- content: "Important Message"
     |-- generatedMemokey3 
       |-- title: "Important numbers"
       |-- content: "1337, 42, 3.14159265359"
  |-- users
     |-- userKey1
       |-- name: "John Doe"
       |-- memos
         |-- memokey1 : true //The values here don't matter, we only need the keys.
         |-- memokey2 : true
         |-- generatedMemokey3 : true
     |-- userKey2
       |-- name: "Max Doe"

Grundlegendes zur Firebase-JSON-Datenbank

Bevor wir uns die Hände mit Code schmutzig machen, muss man verstehen, wie Daten in Firebase gespeichert werden. Im Gegensatz zu relationalen Datenbanken speichert Firebase Daten im JSON-Format. Stellen Sie sich jede Zeile in einer relationalen Datenbank als JSON-Objekt vor (bei dem es sich im Wesentlichen um ein ungeordnetes Schlüsselwertpaar handelt). Der Spaltenname wird also zu einem Schlüssel und der in dieser Spalte für eine bestimmte Zeile gespeicherte Wert ist der Wert. Auf diese Weise wird die gesamte Zeile als JSON-Objekt dargestellt und eine Liste davon stellt eine gesamte Datenbanktabelle dar. Der unmittelbare Vorteil, den ich dafür sehe, ist, dass die Schemaänderung im Vergleich zu alten RDBMS-Systemen wesentlich kostengünstiger wird. Es ist einfacher, einem JSON ein paar weitere Attribute hinzuzufügen, als eine Tabellenstruktur zu ändern.

Hier ein Beispiel-JSON, um zu zeigen, wie Daten in Firebase gespeichert werden:

   {
    "user_base" : {
      "342343" : {
        "email" : "[email protected]",
        "authToken" : "some string",
        "name" : "Kaushal",
        "phone" : "+919916xxxxxx",
        "serviceProviderId" : "firebase",
        "signInServiceType" : "google",
      },
      "354895" : {
        "email" : "[email protected]",
        "authToken" : "some string",
        "name" : "devil",
        "phone" : "+919685xxxxxx",
        "serviceProviderId" : "firebase",
        "signInServiceType" : "github"
      },
      "371298" : {
        "email" : "[email protected]",
        "authToken" : "I am batman",
        "name" : "Bruce Wayne",
        "phone" : "+14085xxxxxx",
        "serviceProviderId" : "firebase",
        "signInServiceType" : "shield"
      }
    },
    "user_prefs": {
      "key1":{
        "data": "for key one"
      },
      "key2":{
        "data": "for key two"
      },
      "key3":{
        "data": "for key three"
      }
    },
    //other structures
  }

Dies zeigt deutlich, wie Daten, die wir in relationalen Datenbanken gespeichert haben, im JSON-Format gespeichert werden können. Als Nächstes wollen wir sehen, wie diese Daten in Android-Geräten gelesen werden.

Daten von der Firebase abrufen

Ich gehe davon aus, dass Sie bereits wissen, wie Sie in Android Studio gradle Abhängigkeiten hinzufügen können. Wenn Sie nicht einfach der Anleitung von hier folgen. Fügen Sie Ihre App in der Firebase-Konsole hinzu, und synchronisieren Sie das Android Studio, nachdem Sie Abhängigkeiten hinzugefügt haben. Es werden nicht alle Abhängigkeiten benötigt, nur Firebase-Datenbank und Firebase-Authentifizierung.

Nun, da wir wissen, wie Daten gespeichert werden und wie Abstufungsabhängigkeiten hinzugefügt werden, sehen wir uns an, wie Sie mit dem importierten Android-SDB (Firebase) Daten abrufen können.

Erstellen Sie eine Firebase-Datenbankreferenz

DatabaseReference userDBRef = FirebaseDatabase.getInstance().getReference();
// above statement point to base tree
userDBRef = DatabaseReference.getInstance().getReference().child("user_base")
// points to user_base table JSON (see previous section)

Von hier aus können Sie mehrere child () - Methodenaufrufe verketten, um auf die Daten zu verweisen, an denen Sie interessiert sind. Wenn beispielsweise die Daten wie im vorherigen Abschnitt beschrieben gespeichert werden und Sie auf Bruce Wayne-Benutzer verweisen möchten, können Sie Folgendes verwenden:

DatabaseReference bruceWayneRef = userDBRef.child("371298");
// 371298 is key of bruce wayne user in JSON structure (previous section)

Oder übergeben Sie einfach die gesamte Referenz an das JSON-Objekt:

DatabaseReference bruceWayneRef = DatabaseReference.getInstance().getReference()
     .child("user_base/371298");
// deeply nested data can also be referenced this way, just put the fully
// qualified path in pattern shown in above code "blah/blah1/blah1-2/blah1-2-3..."

Da wir nun die Referenz der Daten haben, die wir abrufen möchten, können wir Listener verwenden, um Daten in Android-Apps abzurufen. Im Gegensatz zu herkömmlichen Aufrufen, bei denen REST-API-Aufrufe mithilfe von Retrofit oder Volley ausgelöst werden, ist hier ein einfacher Callback-Listener erforderlich, um die Daten abzurufen. Firebase sdk ruft die Callback-Methoden auf und Sie sind fertig.

Es gibt grundsätzlich zwei Arten von Listenern, die Sie anfügen können, einer ist ValueEventListener und der andere ist ChildEventListener (im nächsten Abschnitt beschrieben). Bei jeder Änderung der Daten unter dem Knoten, für den wir Verweise und Listener hinzugefügt haben, geben Wertereignis-Listener die gesamte JSON-Struktur zurück, und der untergeordnete Ereignislistener gibt ein bestimmtes untergeordnetes Element zurück, an dem die Änderung stattgefunden hat. Beide sind auf ihre Weise nützlich. Um die Daten von Firebase abzurufen, können wir einer Firebase-Datenbankreferenz einen oder mehrere Listener hinzufügen (list userDBRef, die wir zuvor erstellt haben).

Hier ist ein Beispielcode (Code-Erklärung nach Code):

userDBRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        User bruceWayne = dataSnapshot.child("371298").getValue(User.class);
        // Do something with the retrieved data or Bruce Wayne
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.e("UserListActivity", "Error occured");
        // Do something about the error
    });

Haben Sie festgestellt, dass der Klassentyp bestanden wurde? DataSnapshot kann JSON-Daten in unsere definierten POJOs konvertieren, indem Sie einfach den richtigen Klassentyp übergeben.

Wenn Ihr Anwendungsfall nicht jedes Mal die gesamten Daten (in unserem Fall user_base-Tabelle) benötigt, wenn eine kleine Änderung auftritt oder Sie die Daten nur einmal abrufen möchten, können Sie die addListenerForSingleValueEvent () - Methode der Datenbankreferenz verwenden. Dadurch wird der Rückruf nur einmal ausgelöst.

userDBRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // Do something
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // Do something about the error
    });

Die obigen Beispiele geben Ihnen den Wert des JSON-Knotens. Um den Schlüssel zu erhalten, rufen Sie einfach an:

String myKey = dataSnapshot.getKey();

Auf untergeordnete Updates achten

Nutzen Sie einen Anwendungsfall wie eine Chat-App oder eine kollaborative Einkaufslisten-App (die im Wesentlichen eine Liste von Objekten erfordert, die mit den Benutzern synchronisiert werden müssen). Wenn Sie die Firebase-Datenbank verwenden und einen Wertereignis-Listener zum übergeordneten Knoten des Chat-Bereichs oder zum übergeordneten Knoten der Einkaufsliste hinzufügen, endet die gesamte Chat-Struktur ab dem Beginn der Zeit (ich meinte den Beginn Ihres Chats), wenn ein Chat-Knoten hinzugefügt wird dh jemand sagt hallo). Das wollen wir nicht. Was uns interessiert, ist nur der neue Knoten oder nur der alte Knoten, der gelöscht oder geändert wurde. Die unveränderten sollten nicht zurückgegeben werden.

In diesem Fall können wir ChildEvenListener verwenden . Ohne weitere Hinweise hier ein Codebeispiel (siehe vorherige Abschnitte für JSON-Beispieldaten):

userDBRef.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String s) {
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String s) {
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String s) {
        //If not dealing with ordered data forget about this
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
    });

Methodennamen sind selbsterklärend. Wie Sie sehen, wenn ein neuer Benutzer hinzugefügt oder eine Eigenschaft eines vorhandenen Benutzers geändert oder ein Benutzer gelöscht oder entfernt wird, wird die entsprechende Rückrufmethode des untergeordneten Ereignislisteners mit relevanten Daten aufgerufen. Wenn Sie also die Benutzeroberfläche zum Beispiel für eine Chat-App auf dem neuesten Stand halten, holen Sie sich die JSON-Analyse von onChildAdded () in POJO und passen Sie sie in Ihre Benutzeroberfläche ein. Denken Sie daran, Ihren Listener zu entfernen, wenn der Benutzer den Bildschirm verlässt.

onChildChanged () gibt den gesamten untergeordneten Wert mit geänderten (neuen) Eigenschaften an.

onChiledRemoved () gibt den entfernten untergeordneten Knoten zurück.

Daten mit Paginierung abrufen

Wenn Sie über eine große JSON-Datenbank verfügen, ist das Hinzufügen eines Wertereignis-Listeners nicht sinnvoll. Die riesige JSON wird zurückgegeben, und das Parsen wäre zeitaufwändig. In solchen Fällen können wir die Paginierung verwenden, um einen Teil der Daten abzurufen und anzuzeigen oder zu verarbeiten. Ein bisschen wie faules Laden oder wie das Abrufen alter Chats, wenn Benutzer auf älteren Chat klicken klicken. In diesem Fall kann Query verwendet werden.

Nehmen wir unser altes Beispiel in den vorherigen Abschnitten. Die Benutzerbasis enthält 3 Benutzer, wenn die Anzahl der Benutzer dreihunderttausend beträgt und Sie die Benutzerliste in Stapel von 50 abrufen möchten:

// class level
final int limit = 50;
int start = 0;

// event level
Query userListQuery = userDBRef.orderByChild("email").limitToFirst(limit)
        .startAt(start)
userListQuery.addValueEventListener(new ValueEventListener() {
    @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
        // Do something
        start += (limit+1);
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // Do something about the error
    });

Hier können Wert- oder untergeordnete Ereignisse hinzugefügt und angehört werden. Rufen Sie die Abfrage erneut auf, um die nächsten 50 abzurufen. Stellen Sie sicher, dass Sie die orderByChild () - Methode hinzufügen. Ohne diese Funktion wird dies nicht möglich sein. Firebase muss die Reihenfolge kennen, nach der Sie paginieren.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow