Android как дождаться завершения метода onComplete перед переходом к следующему коду

#java #android #multithreading

#java #Android #многопоточность

Вопрос:

Я хочу получить логическое значение из моей функции onComplete, прежде чем перейти к следующему шагу.

Моя проблема в том, что когда код доходит до той части, когда мое логическое значение (isLoginSucces) имеет решающее значение для моего кода, он получает только значение false, потому что функция onComplete не достигла того момента, когда она изменяет значение логического значения.

Я попробовал функцию async, но она не сработала, попробовал также AtomicBoolean, тоже не сработало.

После этого я поставил even Thread.sleep(10000). За это время (10 секунд) он, безусловно, изменил значение, но тоже не работает, по-прежнему false, я не понимаю.

     private String loginButtonClicked () {

            mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        ...
                        LoginFragment.this.isLoginSucces = true;
                        Log.d("boolean", "boolean value in onComplete: "   isLoginSucces);
                    } else {
                        ...
                        LoginFragment.this.isLoginSucces = false;
                    }
                }
            });

            //HERE I tried Thread.sleep(10000);
            Log.d("boolean", "boolean value after function: "   isLoginSucces);

            if (LoginFragment.this.isLoginSucces)
                return email;
            else
                return null;

    }
  

Вывод журнала :

2019-03-29 18:45:12 D / boolean: логическое значение после функции: false

2019-03-29 18:45:14 D / boolean: логическое значение в onComplete: true

Комментарии:

1. В общем, вы этого не делаете. Это функция обратного вызова. Это означает, что работа будет выполнена либо в другом потоке, либо в этом потоке, но позже. Есть некоторые ситуации, когда вы можете сделать это безопасно, но не в целом. Вместо этого ваш код должен быть написан так, чтобы не ждать результата. Это ОСОБЕННО верно, если это основная команда — в этом случае она никогда ничего не должна ждать. Это может привести к отказу от ответа, в худшем случае к зависанию

2. Но мне нужна функция onComplete, только таким образом она работает для получения данных из Firebase. Я не знаю другого способа.

3. Правильно — итак, ваш код, который использует результат onComplete, должен перейти в onComplete. Вы не должны ждать его вызова. Вместо этого вы не должны использовать результаты вызова до тех пор, пока это не произойдет, и отображать пользовательский интерфейс загрузки, если это необходимо, до тех пор

4. Да, я понимаю, что вы говорите, но мне нужно, чтобы он возвращал значение, и, как вы знаете, onComplete имеет тип void . Не могу ничего вернуть из него, также не могу извлечь необходимую информацию из переменной, потому что она быстро ее преодолеет.

5. Вам необходимо провести рефакторинг вашего кода, чтобы вызвать функцию в onComplete, которая содержит весь код, выполняемый после вызова этого метода. Этот метод будет недействительным, и все, что требует этой строки, находится в методе, который вы вызываете в onComplete. Это единственный способ убедиться, что результаты готовы к использованию.

Ответ №1:

 public void methodThatCallsLoginButtonClicked() {
    // code before calling loginButtonClicked 

    loginButtonClicked();

    // nothing else that needs the value from login button clicked should be here
}

public void afterLogin(boolean result) {
    // any code that needs the value of the login callback
}

private void loginButtonClicked () {

        mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                afterLogin(task.isSuccessful());
            }
        });

}
  

Ответ №2:

Объявить

 String str_email = ""; 
  

в верхней части вашего кода.

Вставить зависимый код внутри метода oncomplete, удалив оператор return и изменив для:

 private String loginButtonClicked () {

            mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(getActivity(), new OnCompleteListener<AuthResult>() {
                @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    ...
                    LoginFragment.this.isLoginSucces = true;
                    Log.d("boolean", "boolean value in onComplete: "   isLoginSucces);
                } else {
                    ...
                    LoginFragment.this.isLoginSucces = false;
                }

               if (LoginFragment.this.isLoginSucces)
                   str_email = email;
               else
                   str_email = ";

        });
}
  

Выполняйте свой код с

 if(!str_email.equals("")){

//if str_email is different from ""


}
  

Комментарии:

1. Все тот же результат, смотрите журнал: 2019-03-29 19:08:16.423 D / boolean: значение str после функции: 2019-03-29 19:08:17.570 D / boolean: значение str в onComplete: ainkiwi@gmail.com

2. По-прежнему get вне функции onComplete со значением null