Kotlin协程如何以正确的方式调用api



嘿,我想调用api类。我是Coroutines的新手。我尝试了一些代码,但我不确定这是正确的方式做它或不。

  1. 内的LoginHelper有一个函数叫做logout有不止一个函数。我想先执行api调用。然后我想在logout中执行其他函数。

  2. 在<<li>strong> Mainactivity 我正在调用LoginHelper.logout它会结束,然后我需要执行另一行。但是我不想让suspend函数,因为它也占用了其他地方。

我也得到了一个errorProcess:

com.dimen.app, PID: 12496
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1605)

Session.kt

interface Session{
@DELETE("/session/delete")
fun deleteSession(): Call<Void>
}

SessionRepository.kt

suspend fun deleteSession(): RequestResult<Void> {
return apiCall(api.deleteSession())
}

RequestResult是一个密封类

sealed class RequestResult<out T : Any> {
data class Success<out T : Any>(): RequestResult<T>
data class Error(): RequestResult<Nothing>()
fun result(success: (data: T?) -> Unit),error: (error: Error) -> Unit)
}

MainActivity.kt

private fun setupLogout() {
logoutButton.setOnClickListener {
LoginHelper.logout() // need to wait untill this finish
// more logic here....
}
}

LoginHelper.kt

object LoginHelper {
fun logout() {
logD("logout")
deleteSession() // need to wait untill this finish and then excute more function....
} 
private fun deleteSession() {
runBlocking{
apiCall.deleteSession().execute()
}
}
}

永远不要在Android应用程序中使用runBlocking,除非你知道你在做什么。这在99%的情况下都是错误的选择,因为它违背了使用协程的目的。阻塞意味着当前线程等待协程运行其异步代码。但是你不能阻塞主线程,因为这会冻结UI。

因为你的LoginHelper是一个object或单例,如果它要启动协程,它需要自己的CoroutineScope。

可以设置deleteSession()为挂起函数,这样它就可以调用api.deleteSession()挂起函数

可以让logout()启动协程,顺序删除会话,然后执行其他任务。您还可以使它返回已启动的Job,以便其他类可以选择是否直接开始注销,或者在协程中启动并等待注销。

object LoginHelper {
private val scope = CoroutineScope(SupervisorJob() + CoroutineName("LoginHelper"))
fun logout(): Job = scope.launch {
logD("logout")
deleteSession()
// .... more functions that happen after deleteSession() is complete
}
private suspend fun deleteSession() {
Tokenclass.getToken()?.let {
logE("token ::-> $it")
apiCall.deleteSession(it).execute()
}
}
}

如果您希望外部类能够等待logout完成,它可以在自己的协程中对返回的Job调用join(),例如:

logoutButton.setOnClickListener {
lifecycleScope.launch {
LoginHelper.logout().join()
// more logic here....
}
}

如果你不需要在activity中等待它,你就不需要启动协程,也不需要调用join()

最新更新