Kotlin Coroutines如何实现以正确的方式调用api
Kotlin Coroutines how to achieve to call api in right way
嘿,我想从 object class 调用 api。我是协程的新手。我尝试了一些代码,但我不确定这样做是否正确。
在LoginHelper里面有一个叫做logout的函数有不止一个函数。我想先执行 api 调用。然后我想在注销中执行其他功能。
在 Mainactivity 我调用 LoginHelper.logout 它会完成然后我需要执行其他行.但是我不想让挂起功能因为它也在使用其他地方。
我还得到一个错误过程:
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
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()
启动协程以顺序删除会话并随后执行其他任务。你可以让它 return 启动 Job 这样其他 classes 可以选择是简单地启动注销,还是启动并等待协程中的注销。
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()
}
}
}
如果您希望外部 class 能够等待 logout
完成,它可以在自己的 returned Job 上调用 join()
协程,例如:
logoutButton.setOnClickListener {
lifecycleScope.launch {
LoginHelper.logout().join()
// more logic here....
}
}
如果在activity中不需要等待,则不需要启动协程,也不需要调用join()
.
嘿,我想从 object class 调用 api。我是协程的新手。我尝试了一些代码,但我不确定这样做是否正确。
在LoginHelper里面有一个叫做logout的函数有不止一个函数。我想先执行 api 调用。然后我想在注销中执行其他功能。
在 Mainactivity 我调用 LoginHelper.logout 它会完成然后我需要执行其他行.但是我不想让挂起功能因为它也在使用其他地方。
我还得到一个错误过程:
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
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()
启动协程以顺序删除会话并随后执行其他任务。你可以让它 return 启动 Job 这样其他 classes 可以选择是简单地启动注销,还是启动并等待协程中的注销。
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()
}
}
}
如果您希望外部 class 能够等待 logout
完成,它可以在自己的 returned Job 上调用 join()
协程,例如:
logoutButton.setOnClickListener {
lifecycleScope.launch {
LoginHelper.logout().join()
// more logic here....
}
}
如果在activity中不需要等待,则不需要启动协程,也不需要调用join()
.