Как вернуть сообщения об ошибках от сопрограмм - PullRequest
1 голос
/ 24 мая 2019

Я пытаюсь изменить все мои обратные вызовы на сопрограммы, я прочитал о них, и они быстро меняются!

Что я хочу сделать, так это просто войти в систему пользователя, но если логика входа не удалась, уведомитьэто моему докладчику.

Это то, что я сделал

LoginPresenter.kt

class LoginPresenter @Inject constructor(private val signInInteractor: SignInInteractor) : LoginContract.Presenter, CoroutineScope {

    private val job = Job()
    override val coroutineContext: CoroutineContext = job + Dispatchers.Main

override fun signInWithCoroutines(email: String, password: String) {

        launch {
            view?.showProgress()
            withContext(Dispatchers.IO){
                signInInteractor.signInWithCoroutinesTest(email,password)
            }
            view?.hideProgress()
        }

    }
}

И теперь проблема в моем интеракторе, так как его функция приостановки,Я хотел бы вернуть ответ об ошибке, чтобы сделать view.showError(errorMsg) от моего докладчика

SignInInteractor.kt

 override suspend fun signInWithCoroutinesTest(email: String, password: String) {
        FirebaseAuth.getInstance()?.signInWithEmailAndPassword(email, password).addOnCompleteListener { 
            if(it.isSuccessful){
                //Want to notify the presenter that the coroutine has ended succefully
            }else{
                //want to let the courutine know about it.exception.message.tostring
            }
        }

    }

Я делал это с помощью обратных вызовов, которые уведомляли моего докладчика

 override fun signInWithCoroutinesTest(email: String, password: String) {
        FirebaseAuth.getInstance()?.signInWithEmailAndPassword(email, password,listener:OnSuccessCallback).addOnCompleteListener { 
            if(it.isSuccessful){
                listener.onSuccess()
            }else{
                listener.onFailure(it.exception.message.toString())
            }
        }


    }

Вопрос

Как вернуться, если операция прошла успешно из сопрограмм, и уведомить моего докладчика?

Спасибо

Ответы [ 2 ]

1 голос
/ 25 мая 2019

Думайте о сопрограммах, как о обычном синхронном коде.Как бы вы написали это, если бы фоновая работа была завершена немедленно?Может быть, что-то вроде этого:

override fun signInWithCoroutinesTest(email: String, password: String) {
    view?.showProgress()
    if(!signInInteractor.signIn(email,password)) view?.showSignInError()
    view?.hideProgress()
}

Или, если вы хотите отловить ошибку, что-то вроде этого

override fun signInWithCoroutinesTest(email: String, password: String) {
    view?.showProgress()
    try {
        signInInteractor.signIn(email,password))
    } catch(e: AuthenticationException) {
        view?.showError(e.message)
    }
    view?.hideProgress()
}

С сопрограммами вы просто пишете точно такой же код, но сами методы приостанавливаютсяа не блокировать темы.Таким образом, в этом случае signIn будет функцией приостановки, и ее нужно будет вызывать из сопрограммы или другой функции приостановки.Исходя из этого, вы, вероятно, захотите, чтобы внешняя функция приостановила работу, а затем вы бы запустили эту сопрограмму, а не пытались запустить внутри signInWithCoroutinesTest.

Исходный пример не вполне реалистичен.но обычно вы запускаете подобные вещи из существующей области, возможно, связанные с вашей деятельностью или viewModel.В конечном счете, это выглядело бы примерно так:


fun hypotheticalLogic() {
   ...
   viewModelScope.launch {
       signInWithCoroutinesTest(email, password)
   }
   ...
}

override suspend fun signInWithCoroutinesTest(email: String, password: String) {
    view?.showProgress()
    try {
        signInInteractor.signIn(email,password))
    } catch(e: AuthenticationException) {
        view?.showError(e.message)
    }
    view?.hideProgress()
}

Ключевым моментом является просто думать о сопрограммах так же, как и о «нормальном» последовательном коде.

1 голос
/ 24 мая 2019

Вы должны явно приостановить сопрограмму:

override suspend fun signInWithCoroutinesTest(
         email: String, password: String
) = suspendCancellableCoroutine { continuation ->
        FirebaseAuth.getInstance()?.signInWithEmailAndPassword(email, password).addOnCompleteListener { 
            if (it.isSuccessful) {
                continuation.resume(Unit)
            } else {
                continuation.resumeWithException(it.exception)
            }
        }
    }

Кроме того, поскольку ваш код приостановлен и не блокируется, не запускайте его withContext(IO). Просто позвоните прямо из основного потока, вот в чем прелесть сопрограмм.

...