正确使用 CoroutineScope 和 retrofit api 调用

Correct use CoroutineScope with retrofit api call

这是正确的协程和改造使用吗? 我在服务拦截方面遇到了一些问题(通过拦截获取 getAccessTokenBlocking 时出现 RuntimeException),可能是由于 CoroutineScope 使用不正确?

override fun onBindViewHolder(...){
val service = serviceBuilderFactory
            .create(serviceEndpoint, acc)
            .buildWithCache(Service::class.java)

CoroutineScope(Dispatchers.IO)
            .launch(exceptionHandler) {
                val obj = service.getObj() 
    //should i use here for webView.post - withContext(Dispatchers.Main) {  ??????
   // or shoud i use async and resume webView.post after callback?

                webView.post {
                    webView.loadUrl(obj.url)
                    }
             }
}

改造

@GET("/url")
suspend fun getObj(): Obj

这根本不应该在适配器中。每次项目滚动到屏幕上时,您都会触发协程,并且由于您创建了一个 one-off CoroutineScope 来启动每个协程,因此您无法取消它们。如果用户快速旋转屏幕几次,您将在后台拥有大约 30 个您无法取消的过时协同程序 运行,其中许多将执行冗余工作。

相反,您应该在 ViewModel 中进行提取,这样在屏幕旋转时不必重复提取。并使用 viewModelScope 启动协程,以便当它们从当前屏幕超出范围时变得过时时自动取消。

如果您不介意 pre-fetching 每个项目的数据在 RecyclerView 中显示之前,您可以映射您的数据类型以包含获取的 URL,然后再将其公开给您的 Activity/Fragment 通过 LiveData 或 Flow。

如果您只想在项目出现在屏幕上时才延迟加载 URL,您可以使用 async(start = CoroutineStart.LAZY) { ... } 将您的数据类型映射到 Deferred<String>。然后将 CoroutineScope 参数添加到适配器的构造函数,以便 Activity 可以传递 lifecycleScope 或 Fragment 可以传递 viewLifecycleScope,并且您可以使用该范围在适配器中启动协程,协程将自动取消过时的时候。您可以使用这些协程 await() 延迟的 URL.