Buscar..


Observaciones

Otros temas relacionados:

Controlador de eventos Firebase Realtime DataBase

Primero inicialice FirebaseDatabase:

FirebaseDatabase database = FirebaseDatabase.getInstance();

Escribe en tu base de datos:

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

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

Lee de tu base de datos:

// 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());
    }
});

Recuperar datos en eventos de Android:

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);

Configuración rápida

  1. Complete la parte de Instalación y configuración para conectar su aplicación a Firebase.
    Esto creará el proyecto en Firebase.

  2. Agregue la dependencia de Firebase Realtime Database a su archivo build.gradle nivel de build.gradle :

compile 'com.google.firebase:firebase-database:10.2.1'
  1. Configurar las reglas de la base de datos de Firebase

Ahora está listo para trabajar con la base de datos en tiempo real en Android.

Por ejemplo, escribe un mensaje de Hello World en la base de datos debajo de la clave de message .

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

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

Diseño y comprensión de cómo recuperar datos en tiempo real de la base de datos de Firebase

Este ejemplo asume que ya ha configurado una base de datos en tiempo real de Firebase. Si eres un iniciador, infórmate aquí sobre cómo agregar Firebase a tu proyecto de Android.

Primero, agregue la dependencia de la base de datos Firebase al archivo build.gradle de nivel de aplicación:

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

Ahora, creemos una aplicación de chat que almacene datos en la base de datos de Firebase.

Paso 1: Crea una clase llamada Chat

Solo crea una clase con algunas variables básicas requeridas para el chat:

public class Chat{
    public String name, message;
}

Paso 2: Crea algunos datos JSON

Para enviar / recuperar datos a / desde la base de datos de Firebase, debe usar JSON. Supongamos que algunos chats ya están almacenados en el nivel raíz en la base de datos. Los datos de estos chats podrían verse como sigue:

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

Paso 3: Añadiendo los oyentes

Hay tres tipos de oyentes. En el siguiente ejemplo usaremos 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();
    }
});

Paso 4: Agregar datos a la base de datos

Simplemente cree un objeto de clase de chat y agregue los valores de la siguiente manera:

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

Ahora obtenga una referencia al nodo de chats como se hizo en la sesión de recuperación:

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

Antes de comenzar a agregar datos, tenga en cuenta que necesita una referencia más profunda ya que un nodo de chat tiene varios nodos más y agregar un nuevo chat significa agregar un nuevo nodo que contenga los detalles del chat. Podemos generar un nombre nuevo y único del nodo mediante la función push() en el objeto DatabaseReference , que devolverá otra DatabaseReference , que a su vez apunta a un nodo recién formado para insertar los datos de chat.

Ejemplo

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

La función setValue() se asegurará de que se onDataChanged funciones onDataChanged de la aplicación (incluido el mismo dispositivo), que es el oyente adjunto del nodo "chats".

Desnormalización: Estructura de base de datos plana

La desnormalización y una estructura de base de datos plana son necesarias para descargar de manera eficiente llamadas separadas. Con la siguiente estructura, también es posible mantener relaciones bidireccionales. La desventaja de este enfoque es que siempre debe actualizar los datos en varios lugares.

Por ejemplo, imagine una aplicación que le permita al usuario almacenar mensajes para sí mismo (memos).

Estructura de base de datos plana deseada:

|--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"

La clase memo usada.

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;
    }
}

Recuperando los memos de un usuario

//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) { }
    }

Creando un memo

//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);

Después de la inserción, o la base de datos se ve así:

|--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"

Entendiendo la base de datos JSON de base de fuego

Antes de ensuciarnos las manos con el código, creo que es necesario comprender cómo se almacenan los datos en la base de fuego. A diferencia de las bases de datos relacionales, firebase almacena datos en formato JSON. Piense en cada fila de una base de datos relacional como un objeto JSON (que básicamente es un par de clave-valor desordenado). Por lo tanto, el nombre de la columna se convierte en clave y el valor almacenado en esa columna para una fila en particular es el valor. De esta manera, toda la fila se representa como un objeto JSON y una lista de estos representa una tabla de base de datos completa. El beneficio inmediato que veo para esto es que la modificación del esquema se convierte en una operación mucho más barata en comparación con los RDBMS antiguos. Es más fácil agregar un par de atributos más a un JSON que alterar una estructura de tabla.

Aquí hay un JSON de muestra para mostrar cómo se almacenan los datos en firebase:

   {
    "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
  }

Esto muestra claramente cómo los datos que utilizamos para almacenar en bases de datos relacionales se pueden almacenar en formato JSON. A continuación veamos cómo leer estos datos en dispositivos Android.

Recuperando datos de base de fuego

Voy a asumir que ya sabes acerca de la adición de dependencias de gradle base de fuego en Android Studio. Si no sigues la guía desde aquí . Agrega tu aplicación en la consola firebase, gradle sync android studio después de agregar dependencias. No se necesitan todas las dependencias, solo base de datos firebase y autenticación firebase.

Ahora que sabemos cómo se almacenan los datos y cómo agregar dependencias de Gradle, veamos cómo usar el SDK de Android de base de fuego importado para recuperar datos.

crear una referencia de base de datos de base de fuego

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)

desde aquí puede encadenar varias llamadas de método child () para señalar los datos que le interesan. Por ejemplo, si los datos se almacenan como se muestra en la sección anterior y desea señalar al usuario de Bruce Wayne, puede usar:

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

O simplemente pase la referencia completa al objeto JSON:

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..."

Ahora que tenemos la referencia de los datos que queremos obtener, podemos usar oyentes para obtener datos en aplicaciones de Android. A diferencia de las llamadas tradicionales en las que se activan las llamadas de la API REST mediante retrofit o volley, aquí se requiere un simple detector de devolución de llamada para obtener los datos. Firebase SDK llama a los métodos de devolución de llamada y ya está.

Básicamente, puede adjuntar dos tipos de oyentes, uno es ValueEventListener y el otro es ChildEventListener (descrito en la siguiente sección). Para cualquier cambio en los datos bajo el nodo al que tenemos referencias y escuchas agregadas, los escuchas de eventos de valor devuelven la estructura JSON completa y el oyente de eventos hijo devuelve hijos específicos donde ocurrió el cambio. Ambos son útiles a su manera. Para obtener los datos de la base de fuego, podemos agregar uno o más escuchas a una referencia de base de datos de la base de fuego (lista de usuarios DBRef que creamos anteriormente).

Aquí hay un código de ejemplo (explicación del código después del código):

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
    });

¿Notaste que el tipo de clase pasó? DataSnapshot puede convertir datos JSON en nuestros POJO definidos, simplemente pase el tipo de clase correcto.

Si su caso de uso no requiere todos los datos (en nuestra tabla user_base) cada vez que ocurre un pequeño cambio o dice que desea obtener los datos solo una vez , puede usar el método addListenerForSingleValueEvent () de referencia de la base de datos. Esto dispara la devolución de llamada sólo una vez.

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

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

Las muestras anteriores le darán el valor del nodo JSON. Para obtener la clave simplemente llame:

String myKey = dataSnapshot.getKey();

Escuchando actualizaciones de niños

Tome un caso de uso, como una aplicación de chat o una aplicación de lista de compras colaborativa (que básicamente requiere una lista de objetos para sincronizar a los usuarios). Si usa la base de datos de base de fuego y agrega un detector de eventos de valor al nodo primario del chat o al nodo primario de la lista de la compra, terminará con la estructura completa del chat desde el principio del tiempo (me refiero al comienzo del chat) cada vez que se agregue un nodo del chat ( es decir, cualquiera dice hola). Si no queremos hacerlo, lo que nos interesa es solo el nuevo nodo o solo el nodo anterior que se eliminó o modificó, los que no se han modificado no deben devolverse.

En este caso podemos usar ChildEvenListener . Sin más adiós, aquí hay un ejemplo de código (ver las secciones previas para datos de muestra JSON):

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) {
    });

Los nombres de los métodos son auto explicativos. Como puede ver, cada vez que se agrega un nuevo usuario o se modifica alguna propiedad del usuario existente o se elimina o elimina el usuario, se llama al método de devolución de llamada apropiado del oyente de eventos secundarios con datos relevantes. Por lo tanto, si mantiene la interfaz de usuario actualizada para, por ejemplo, la aplicación de chat, obtenga el JSON de onChildAdded () parse en POJO y colóquelo en su interfaz de usuario. Solo recuerda eliminar a tu oyente cuando el usuario salga de la pantalla.

onChildChanged () proporciona todo el valor secundario con propiedades modificadas (nuevas).

onChiledRemoved () devuelve el nodo secundario eliminado.

Recuperando datos con paginación

Cuando tiene una gran base de datos JSON, agregar un valor de escucha de eventos no tiene sentido. Devolverá el enorme JSON y analizarlo llevaría mucho tiempo. En tales casos, podemos usar la paginación y obtener parte de los datos y mostrarlos o procesarlos. Algo así como la carga perezosa o como buscar chats antiguos cuando el usuario hace clic en mostrar chat anterior. En este caso se puede utilizar la consulta .

Tomemos nuestro ejemplo anterior en secciones anteriores. La base de usuarios contiene 3 usuarios, si crece hasta decir 3 cientos mil usuarios y desea obtener la lista de usuarios en lotes de 50:

// 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
    });

Aquí se pueden agregar y escuchar eventos de valor o secundarios. Vuelva a llamar a la consulta para obtener los próximos 50. Asegúrese de agregar el método orderByChild () , esto no funcionará sin eso. Firebase necesita saber el orden por el cual está paginando.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow