java - guardar - espera hasta que Firebase recupere datos
guardar datos en firebase android (5)
Quiero crear un método que devuelva un valor child
en FireBase
. Intenté hacer algo como esto:
public String getMessage(){
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
message = (String) dataSnapshot.getValue();
Log.i("4r398", "work");
}
@Override
public void onCancelled(FirebaseError firebaseError) {
Log.e("error", firebaseError.getMessage());
}
});
return message;
}
El problema es que el método devuelve un null
probablemente porque el método no espera hasta que el oyente finaliza y devuelve un null
porque es el valor predeterminado del message
. ¿Cómo puedo hacer que este método espere hasta que se produzca la escucha y luego devolver el valor?
Como @ CMikeB1 comentó sobre otra respuesta en el mundo java cuando tratamos con servlets y servicios, usamos llamadas de sincronización para realizar operaciones, sería útil tener ambas opciones en sdk firebase admin para que el desarrollador pueda elegir cuál usar. Dependiendo de su uso del caso.
Hice mi implementación de espera para leer los datos de sincronización usando ApiFuture, que es la interfaz actual adoptada por el SDK del administrador de base de fuego. Aquí hay un enlace !
public DataSnapshot getMessage() {
final SettableApiFuture<DataSnapshot> future = SettableApiFuture.create();
databaseReference.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
future.set(dataSnapshot);
}
@Override
public void onCancelled(DatabaseError databaseError) {
future.setException(databaseError.toException());
}
});
try {
return future.get();
} catch(InterruptedException | ExecutionException e) {
e.printStackTrace();
return null;
}
}
Dejaré esto aquí para ayudar a cualquiera que se enfrente con el mismo problema que yo. El código de @Tirupati Singh se ve bien, pero escribí mi respuesta debajo de él, por qué no me funcionó. Usando el tipo atómico trabajado -
public AtomicInteger getMessage(){
final AtomicBoolean done = new AtomicBoolean(false);
final AtomicInteger message1 = new AtomicInteger(0);
//assuming you have already called firebase initialization code for admin sdk, android etc
DatabaseReference root = FirebaseDatabase.getInstance().getReference("server");
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
message1.set((Integer) dataSnapshot.getValue());
done.set(true);
}
public void onCancelled(DatabaseError error) {
// TODO Auto-generated method stub
}
});
while (!done.get());
return message1;
}
Tenga en cuenta que la función solo puede devolver el tipo de mensaje Integer. No pude hacer que funcione para String, ya que no es un tipo atómico para String. ¡Espero que esto ayude!
Hacer una interfaz
public interface OnGetDataListener {
//this is for callbacks
void onSuccess(DataSnapshot dataSnapshot);
void onStart();
void onFailure();
}
Declara la siguiente función readData ()
public void readData(Firebase ref, final OnGetDataListener listener) {
listener.onStart();
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
listener.onSuccess(dataSnapshot);
}
@Override
public void onCancelled(FirebaseError firebaseError) {
listener.onFailure();
}
});
}
Llame a la función readData () de la siguiente manera
readData(root.child("MessagesOnLaunch").child("Message"), new OnGetDataListener() {
@Override
public void onSuccess(DataSnapshot dataSnapshot) {
//got data from database....now you can use the retrieved data
}
@Override
public void onStart() {
//when starting
Log.d("ONSTART", "Started");
}
@Override
public void onFailure() {
Log.d("onFailure", "Failed");
}
});
Se puede llamar a readData () dentro de su método getMessage () o incluso dentro de onCreate ()
No utilice Firebase como funciones que devuelven valores, va en contra de su naturaleza asíncrona.
La estructura del código del plan que permite a Firebase realizar su tarea y luego dentro del cierre (bloque) ir al siguiente paso.
En su código, por ejemplo, cambie la función para que no devuelva nada y dentro de onDataChange, ya que la última línea llama a la siguiente función para actualizar su interfaz de usuario.
Puedes usar CountDownLatch. Así es como puedes usarlo.
public String getMessage(){
CountDownLatch done = new CountDownLatch(1);
final String message[] = {null};
root.child("MessagesOnLaunch").child("Message").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
message[0] = (String) dataSnapshot.getValue();
System.out.println("worked");
done.countDown();
}
@Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("failed"+firebaseError.getMessage());
}
});
try {
done.await(); //it will wait till the response is received from firebase.
} catch(InterruptedException e) {
e.printStackTrace();
}
return message[0];
}