1

I've written a code to create a new account using Firebase Auth:

public static int signUp(String email, String password) {
  mAuth.createUserWithEmailAndPassword(email, password)
      .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
        @Override
        public void onComplete(@NonNull Task<AuthResult> task) {
          if (task.isSuccessful()) {
            Log.i("accountMessage", "User has registered successfully!");
          } else {
            try {
              throw task.getException();
            } catch (FirebaseAuthUserCollisionException e) {
              Log.i("accountMessage", "User is registered already!");
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        }
      });

  Log.i("accountMessage", "I want that this message works lastest!");
}

I can catch accountMessages using LogCat. Normally I have to first see "User is registered already!" message but, I can't see it first: Android LogCat accountMessage I've seen on Google APIs for Android that OnCompleteListener called on main application thread, but I cannot understand that if OnCompleteListener called on main application thread (I know that main application thread is same UI Thread on Android), how is it working as asynchronously? Shouldn't it work synchronously if it is working on the main application thread? I mean shouldn't we see first "User is registered already!", then "I want that this message works lastest!" message? Is there a way for OnCompleteListener works on UI Thread as synchronously if is it working as asynchronously?


Edit 2:

In fact, the asynchronously operation of the onComplete causes the res[0] in the following code to return from the signUp method before it is given the value in the onComplete:

public static int signUp(String email, String password) {
  final int[] res = new int[1];
  mAuth.createUserWithEmailAndPassword(email, password)
      .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
        @Override
        public void onComplete(@NonNull Task<AuthResult> task) {
          if (task.isSuccessful()) {

            res[0] = 123;

            // We can't use 'return 123;' in here...

          }
        }
      });

  // You can see that value of res[0] is "0", because not given "123" value.
  // Must be: First, given "123" value to res[0], after then return res[0];
  return res[0];
}
İbrahim
  • 991
  • 1
  • 10
  • 32

1 Answers1

2

The work happens off the main thread, so that it doesn't block you app. The onComplete callback is then scheduled onto the main thread, so that you update the UI without having to do the context switch yourself.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks. Well, sometimes we want to run it on just UI thread. Because we can give a value to a variable in `onComplete` and then want return that variable with new value. We can't return it in `onComplete`. I mean, for example we have `a[0]` and there is `a[0] = 123;` in `onComplete`, then we return `a[0]` in `signUp` method. How can we return this `a[0]` from signUp method with its new value (123)? I can't return `a[0]` with its new value from `signUp`, because `onComplete` is asynchronously. – İbrahim Apr 25 '19 at 21:30
  • 1
    I'm not sure I understand what you're trying to accomplish here. If you want to update the UI, you can do that in the `onComplete`. If you want to do more work that shouldn't happen on the main thread in response to `onComplete`, you can kick off another background thread. – Frank van Puffelen Apr 25 '19 at 22:23
  • 1
    The behavior you're seeing is caused by the asynchronous nature of Firebase operations. By the time `return res[0];` runs, the `onDataChange` hasn't been called yet. There is no way to make the code wait for the operation to complete, so you have to architect your code around the asynchronous behavior. For example, see: https://medium.com/google-developers/why-are-firebase-apis-asynchronous-callbacks-promises-tasks-e037a6654a93 and https://stackoverflow.com/questions/50434836/getcontactsfromfirebase-method-return-an-empty-list/50435519#50435519 – Frank van Puffelen Apr 26 '19 at 01:17
  • Thanks. You solved my problem. I've used callback method with interface. – İbrahim Apr 26 '19 at 19:30
  • Yeah, the custom interface typically works well. I should update it for Kotlin, as the amount of plumbing is substantially less there. – Frank van Puffelen Apr 26 '19 at 23:19