Firestore OncompleteListener [duplicate]

帅比萌擦擦* 提交于 2021-02-05 07:33:13

问题


I want to see what is the error in this code for the executiom, when i compile it it just returns the values of log 1,3,2 , and i wanto log 2 to be before the 3

Log.d("1", "antes de validar");
    DocumentReference docRef = db.getDb().collection("Usuarios").document(Correo);
    docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            Log.d("2", "validar");
            if (task.isSuccessful()) {
                DocumentSnapshot document = task.getResult();
                if (document.exists()) {
                    setBanderaValidarCorreoDB(true);
                    return;
                } else {
                    setBanderaValidarCorreoDB(false);
                    return;
                }
            } else {
                Toast.makeText(contextoRegistro, "ERROR al Realizar la validacion de Correo"+ task.getException(), Toast.LENGTH_SHORT).show();
                setBanderaValidarCorreoDB(false);
                return;
            }
        }
    });
    Log.d("3", "despues de validar");
    return BanderaValidarCorreoDB;
}

This is how it shows

07-08 13:47:56.968 6027-6027/felipe.monumentosfinalcertamen D/1: antes de 
 validar
07-08 13:47:56.980 6027-6027/felipe.monumentosfinalcertamen D/3: despues de validar
07-08 13:47:57.071 6027-6052/felipe.monumentosfinalcertamen W/EGL_emulation: eglSurfaceAttrib not implemented
07-08 13:47:57.071 6027-6052/felipe.monumentosfinalcertamen W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xe2b2a700, error=EGL_SUCCESS
07-08 13:47:57.149 6027-6052/felipe.monumentosfinalcertamen W/EGL_emulation: eglSurfaceAttrib not implemented
07-08 13:47:57.149 6027-6052/felipe.monumentosfinalcertamen W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0xe2cf7540, error=EGL_SUCCESS
07-08 13:47:57.177 6027-6052/felipe.monumentosfinalcertamen V/RenderScript: 0xeff9b600 Launching thread(s), CPUs 4
07-08 13:47:58.483 6027-6027/felipe.monumentosfinalcertamen D/2: validar
07-08 13:52:35.654 6027-6068/felipe.monumentosfinalcertamen I/FirebaseAuth: [FirebaseAuth:] Loading module via FirebaseOptions.
    [FirebaseAuth:] Preparing to create service connection to gms implementation

回答1:


The data is loaded from Cloud Firestore asynchronously. By the time your return BanderaValidarCorreoDB, the data hasn't loaded yet. There is no way to make the return statement wait for the data to be loaded. That is by design, and I highly recommend embracing programming against asynchronous APIs sooner rather than later.

The solution can be one of two things:

  1. Move the code that needs the data into onComplete.
  2. Pass your own callback interface into your helper function that loads the data.

Moving the code that needs the data into onComplete is the simplest. It's similar to how you already call setBanderaValidarCorreoDB, but then also call the code that needs the value of BanderaValidarCorreoDB:

public void onComplete(@NonNull Task<DocumentSnapshot> task) {
    if (task.isSuccessful()) {
        DocumentSnapshot document = task.getResult();
        if (document.exists()) {
            setBanderaValidarCorreoDB(true);
        } else {
            setBanderaValidarCorreoDB(false);
        }
    } else {
        Toast.makeText(contextoRegistro, "ERROR al Realizar la validacion de Correo"+ task.getException(), Toast.LENGTH_SHORT).show();
        setBanderaValidarCorreoDB(false);
    }
    doSomethingWithBanderaValidarCorreoDB(BanderaValidarCorreoDB);
}

This is simple, but reduces the reuse of you helper function a bit. So you can also define your own interface, and pass that into your helper function to call back. Code may be simpler to follow than words here, so:

public interface BanderaValidarCorreoDBCallback {
  void onCallback(boolean value);
}
void getBanderaValidarCorreoDB(BanderaValidarCorreoDBCallback callback)
    DocumentReference docRef = db.getDb().collection("Usuarios").document(Correo);
    docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            if (task.isSuccessful()) {
                DocumentSnapshot document = task.getResult();
                if (document.exists()) {
                    setBanderaValidarCorreoDB(true);
                    return;
                } else {
                    setBanderaValidarCorreoDB(false);
                    return;
                }
            } else {
                Toast.makeText(contextoRegistro, "ERROR al Realizar la validacion de Correo"+ task.getException(), Toast.LENGTH_SHORT).show();
                setBanderaValidarCorreoDB(false);
                return;
            }
            callback(BanderaValidarCorreoDB);
        }
    });
}

And then you invoke it as:

getBanderaValidarCorreoDB(new BanderaValidarCorreoDBCallback() {
  @Override
  public void onCallback(boolean value) {
    System.out.println("Loaded "+value)
  }
});

This is an extremely common source of confusion for developers new to asynchronous programming. So I also recommend you check out some of these other sources:

  • How to check a certain data already exists in firestore or not
  • Setting Singleton property value in Firebase Listener (which also shows that waiting sometimes is possible, but not reliably on Android).
  • getContactsFromFirebase() method return an empty list
  • Android: Get a Pojo List from Firebase during the first initialization from the Service Class
  • Doug's great blog post on asynchronous APIs.

While many of these are for the Firebase realtime database, the problem and solution are the same across all technologies.



来源:https://stackoverflow.com/questions/51234670/firestore-oncompletelistener

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!