如何从协程返回错误响应

时间:2019-05-24 13:37:46

标签: android kotlin coroutine kotlin-coroutines android-mvp

我正在尝试将所有回调都更改为协程,我已经阅读了有关它们的内容,它们令人着迷!

我要完成的只是登录用户,但是如果登录逻辑失败,则将其通知给我的演示者。

这就是我所做的

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 个答案:

答案 0 :(得分:1)

您必须明确暂停协程:

userID  roleID
1   1
2   1
3   1
1   2
2   2
3   2
1   3
2   3
3   3

此外,由于您的代码可挂起并且不会阻塞,因此请勿运行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) } } } 。只需直接从主线程中调用它,这就是协程的美丽。

答案 1 :(得分:1)

像常规的同步代码一样思考协程。如果后台工作立即完成,您将如何写?也许是这样的:

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()
}

关键是想想协程与“常规”顺序代码相同。