以下代码如何在 Android 上运行

问题描述 投票:0回答:2

在 Philip Lackner 的教程之一中,他正在进行网络调用和 UI 更改,如下所示:

        lifecycleScope.launchWhenCreated {
        binding.progressBar.isVisible = true
        val response = try {
            RetrofitInstance.api.getTodos()
        } catch(e: IOException) {
            Log.e(TAG, "IOException, you might not have internet connection")
            binding.progressBar.isVisible = false
            return@launchWhenCreated
        } catch (e: HttpException) {
            Log.e(TAG, "HttpException, unexpected response")
            binding.progressBar.isVisible = false
            return@launchWhenCreated
        }
        if(response.isSuccessful && response.body() != null) {
            todoAdapter.todos = response.body()!!
        } else {
            Log.e(TAG, "Response not successful")
        }
        binding.progressBar.isVisible = false
    }

这里是指向他的代码的指针:https://github.com/philipplackner/RetrofitCrashCourse/blob/master/app/src/main/java/com/plcoding/retrofitcrashcourse/MainActivity.kt

lifecycleScope 默认绑定到主线程,这意味着除非我们更改范围,否则上面代码中的改造网络调用将在主线程上运行。

这个说法是否正确,如果不正确,为什么?

android kotlin retrofit retrofit2 kotlin-coroutines
2个回答
0
投票

有点复杂,但我会尝试根据我在 Retrofit 代码中探索时发现的内容来解释它。

是的,你确实在主调度器上运行调用

RetrofitInstance.api.getTodos()
(隐含地通过
lifecycleScope
),但是......

,你没有在主线程上运行它。在幕后,Retrofit 中的挂起功能是通过使用

suspendCancellableCoroutine
enqueue(...)
的组合实现的,如源代码本身所示

suspend fun <T> Call<T>.awaitResponse(): Response<T> {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        continuation.resume(response)
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }
}

考虑到这一点,

enqueue(...)
最终(在兔子洞的某个地方)在另一个执行者上执行实际的网络请求,因此当您从主调度程序调用它时,它不会导致任何
NetworkOnMainThread
违规。为什么?好吧,它实际上并没有在主线程上进行任何网络调用,oer se.

希望能澄清一点。 :)


0
投票

简短说明:在调用挂起函数时,你永远不必担心你在哪个线程或调度程序上,因为适当的挂起函数不会阻塞。如果它需要一个特定的调度程序,它会在内部使用

withContext
委托给它。在 Retrofit 的情况下,它根本不使用调度程序——它使用 Retrofit 自己的线程池并使用
suspendCancellableCoroutine
.

挂起

由有能力的 Kotlin 用户设计的任何库都将具有遵循相同约定的挂起函数。暂停功能永远不会阻塞。

© www.soinside.com 2019 - 2024. All rights reserved.