0

In the below example, I call a method signinUser(username, password) This then runs through Firebase to determine if the user has successfully or unsuccessfully been able to sign in. However, it takes Firebase a short amount of time to do this, which by that time the method has already returned with the original value, before being updated by the successful-ness / unsuccessful-ness of the sign in process.

How would I go about returning the method once the Firebase authentication has done it's thing. I am aware I could put a timer on when the return statement is called, however, I'm not sure how that'd work as slow internet connects could cause it to take longer than the given amount set by a timer.

My code is as follows:

public AuthSuccess signinUser(String username, String password) {
        mAuth.signInWithEmailAndPassword(username + "@debugrestaurant.com", password)
                .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (task.isSuccessful()) {
                            Toast.makeText(context, "Successful!", Toast.LENGTH_SHORT).show();
                            authSuccess = new AuthSuccess(true, null);
                        } else {
                            Toast.makeText(context, "Unsuccessful!", Toast.LENGTH_SHORT).show();
                            authSuccess = new AuthSuccess(false, task.getException());
                            Toast.makeText(context, "Exception: " + authSuccess.getException().getLocalizedMessage(), Toast.LENGTH_SHORT).show();
                        }
                    }
                });
        return authSuccess;
    }

Please note that the class AuthSuccess is simply an object I've created to collect whether or not the sign in was successful, and if not, to collect the exception.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Luke C
  • 140
  • 2
  • 12

2 Answers2

1

You cannot return something now that hasn't been loaded yet. With other words, you cannot simply use the authSuccess object outside the onComplete() method because it will always be null due the asynchronous behaviour of this method. This means that by the time you are trying to return that result outside that method, the data hasn't finished loading yet from the database and that's why is not accessible. A quick solve for this problem would be to use the value of authSuccess only inside the onComplete() method, otherwise I recommend you see the last part of my anwser from this post in which I have exaplined how it can be done using a custom callback. You can also take a look at this video for a better understanding.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Thanks for your help. I wasn't sure it could be done, but the clarification confirms it can't. I think the comment by @BakonJarser is actually quite a good way of getting around the issue, however yours are just as good. :) – Luke C May 08 '18 at 21:21
  • Unfortunately, changing the method signature to void will not solve the asynchronous issue. You can solve this only if your waiting for the data. – Alex Mamo May 08 '18 at 21:32
  • I see. I will look further into this issue tomorrow – Luke C May 08 '18 at 21:33
  • Have you tried my solution above? Is there everything alright? – Alex Mamo May 09 '18 at 08:04
  • I've had a look at your post and video which I'm sure are very useful, however I'm having troubles understanding some of it as I am not familiar with certain things you use. However, I have created an alternate solution which likely isn't as good as yours, but it works just fine for now. – Luke C May 09 '18 at 15:24
  • Do you think that my answer helped you? – Alex Mamo May 09 '18 at 16:13
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/170706/discussion-between-idleapps-inc-and-alex-mamo). – Luke C May 09 '18 at 16:21
  • Sorry I thought I did. I've done it now. Thanks again for your help :) – Luke C May 09 '18 at 16:28
0

Your old code is probably something like this

public void onSignInClick(){
    AuthSuccess result = signinUser(username, password);
    if(result.success){
        startMainActivity();
    }else{
        showErrorPopUp();
    }
}

Change this to:

public void onSignInClick(){
    signinUser(username, password);
}
protected void handleLoginResult(AuthSuccess result){
    if(result.success){
        startMainActivity();
    }else{
        showErrorPopUp();
    }
}

And at the very end of your onComplete method do:

handleLoginResult(authSuccess);
Dennis K
  • 1,828
  • 1
  • 16
  • 27