【问题标题】:How to return error responses from Coroutines如何从协程返回错误响应
【发布时间】:2019-05-24 13:37:45
【问题描述】:

我正在尝试将我的所有回调更改为协程,我已经阅读过它们并且它们很吸引人!

我想要完成的只是登录一个用户,但如果登录逻辑失败,请通知我的演示者。

这是我做的

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


    }

问题

协程操作成功后如何返回并通知我的presenter?

谢谢

【问题讨论】:

  • 我认为你可以使用普通的try catch。 ` 启动 { 尝试 { firebaseAuth.signInWithEmailAndPassword(email, pass).await() startMainActivity() } catch (e: Exception) { showError(e.localizedMessage) } } `

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


【解决方案1】:

您必须显式挂起协程:

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)。直接从主线程调用,这就是协程的美妙之处。

【讨论】:

  • 嗨,Marko,非常感谢您花时间回答,我有两个问题,首先,我如何在调用 signInInteractor.signInWithCoroutinesTest( email,password) ,通过删除 withContext(io) 你的意思只是从我的角度调用 presenter.signInWithCoroutines() ,仅此而已?谢谢
  • 1.你捕获了signInWithCoroutinesTest 抛出的异常。 2. 是的,解开withContext(IO) {} 块。
  • 我只是在解释如何进行“检索延续异常”,而不是提供架构建议。设计您的代码以在最合适的位置捕获异常。
  • 是的,我的意思是,从我的演示者那里,我可以在不尝试捕获的情况下检索 continuation.resume 吗?这是我唯一需要完全理解的事情
  • signInWithCoroutine 的调用在继续恢复时完成。然后你的演示者代码的其余部分运行。
【解决方案2】:

将协同程序视为正常的同步代码。如果后台工作立即完成,你会怎么写?也许是这样的:

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 将是一个挂起函数,需要从协程或其他挂起函数中调用。基于此,您可能希望外部函数暂停,然后启动 that 协程,而不是尝试在 signInWithCoroutinesTest 内部启动。

最初的例子并不完全现实,但通常你会从现有的范围内启动这种东西,可能与你的活动或视图模型相关联。最终,它看起来像这样:


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

关键在于将协程与“正常”顺序代码相同。

【讨论】:

    猜你喜欢
    • 2014-01-09
    • 2018-04-23
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 2021-01-08
    • 2019-09-10
    相关资源
    最近更新 更多