首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Kotlin协同器如何实现对api的正确调用

Kotlin协同器如何实现对api的正确调用
EN

Stack Overflow用户
提问于 2021-08-09 13:21:28
回答 1查看 3.3K关注 0票数 3

嘿,我想从对象类调用api。我是新来的。我尝试了一些代码,但我不确定它是否正确。

  1. LoginHelper中,有一个称为注销的函数,有多个该函数。我想先执行api调用。然后我想在注销中执行其他功能。
  2. Mainactivity中,我调用LoginHelper.logout,它将完成,然后我需要执行其他行。但我不想让挂起功能,因为它也在使用其他地方。

我还得到了errorProcess:

代码语言:javascript
运行
复制
com.dimen.app, PID: 12496
    android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1605)

Session.kt

代码语言:javascript
运行
复制
interface Session{
    @DELETE("/session/delete")
    fun deleteSession(): Call<Void>
}

SessionRepository.kt

代码语言:javascript
运行
复制
suspend fun deleteSession(): RequestResult<Void> {
        return apiCall(api.deleteSession())
}

RequestResult是密封级

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
private fun setupLogout() {
    logoutButton.setOnClickListener {
        LoginHelper.logout() // need to wait untill this finish
        // more logic here....
    }
}

LoginHelper.kt

代码语言:javascript
运行
复制
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()
       }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-08-09 13:59:26

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

由于您的LoginHelper是object或单例,如果要启动协同服务,它需要自己的CoroutineScope。

您可以使deleteSession()成为一个挂起函数,这样它就可以调用api.deleteSession()挂起函数。

您可以让logout()启动一个协同线,以便依次删除会话并随后执行其他任务。您可以让它返回已启动的作业,以便其他类可以选择是简单地启动注销,还是在协同线中启动和等待注销。

代码语言:javascript
运行
复制
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完成,它可以在自己的协同线中调用返回的作业的join(),例如:

代码语言:javascript
运行
复制
logoutButton.setOnClickListener {
    lifecycleScope.launch {
        LoginHelper.logout().join()
        // more logic here....
    }
}

如果您不需要在活动中等待它,则不需要启动协同线,也不需要调用join()

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68712809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档