在Android中,如何通过Kotlin协程处理多个API调用

在Android中,如何通过Kotlin协程处理多个API调用

在Android开发中,如何使用Kotlin协程处理多个API调用的示例呢?假设我们已经对Kotlin协程有了一定的了解,包括定义、简单用例和示例等。现在,让我们来看一些真实的Android场景或用例。我们将从一个关于协程作用域的简单问题开始,比如生命周期作用域。

协程问题

问题 #1:如果我们在协程生命周期作用域中运行任何内容而没有提及分发器会发生什么呢?

kotlin 复制代码
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    lifecycleScope.launch {
        val s1 = someTask()
        Log.d(TAG, s1)
    }
}

suspend fun someTask(): String {
    // 我不相信你,给我看看当前线程
    Log.d(TAG, "当前运行的线程 ${Thread.currentThread().name}")
    delay(2000) // 模拟延迟以进行演示
    return "任务的结果"
}

问题 #2

如果它在主线程中运行,那么...

如果我们在协程挂起函数调用之后在作用域外打印一些东西到TextView中会发生什么?

kotlin 复制代码
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    lifecycleScope.launch {
        val s1 = someTask()
        Log.d(TAG, s1)
    }
    binding.myTextView.text = "挂起函数调用之后"
}

问题#3

更复杂一些,我们加一个while循环,那么结果会怎么样呢?会不会导致UI线程出现ANR呢?想要知道答案,请自行运行代码看看结果。

kotlin 复制代码
lifecycleScope.launch {
    val s1 = someTask()
    Log.d(TAG, s1)
}
binding.myTextView.text = "挂起函数调用之后"
while (true) {
    //假设这是模拟UI任务,比如动画或进度旋转,正在进行的UI
    //我们的主线程现在应该始终忙碌
    Log.d(TAG, "我是UI模拟任务")
}

解决方案

用例 #1

我们必须进行两个API调用,第一个API调用将返回一个Auth令牌。然后我们必须使用这个令牌调用第二个API。

简而言之,我们的第二个API依赖于我们第一个API调用的结果。

kotlin 复制代码
lifecycleScope.launch {
    val token  = firstApiCall()
    Log.d(TAG, "token是 $token")
    val result = secondApiCall(token)
    Log.d(TAG, "结果是 $result")
}

suspend fun firstApiCall(): String {
    // 执行API调用1
    delay(2000) // 模拟延迟以进行演示
    return "1234"
}

suspend fun secondApiCall(token: String): String {
    // 执行API调用2
    delay(2000) // 模拟延迟以进行演示
    return "API调用结果 $token"
}

就这样了?是的,就是这样!

但等等!这并不是一个真实的使用ViewModel和MVVM模式进行API调用的示例。

好的,我们来看一些真实的代码。

kt 复制代码
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class TestViewModel: ViewModel() {

    fun secondApiCall() {
        viewModelScope.launch {
            try {
                val token  = getMyToken(isSuccess = true)
                Log.d(TAG, "token is $token")

                //Now make your second API call here using this token
                //repository.getMyData(token)

            } catch (ex: Exception) {

            }
        }
    }

    private suspend fun getMyToken(isSuccess: Boolean): String? {
        val deferred = CompletableDeferred<String?>()
        if (isSuccess) {
            delay(1000)
            deferred.complete("1234")
        } else {
            delay(1000)
            deferred.completeExceptionally(Throwable("Error"))
        }
        return deferred.await()
    }
}

不必进行两次API调用,因为第二次调用依赖于第一次调用!你可以直接调用secondApiCall()函数,它会获取你的令牌。它会等待认证令牌返回,然后使用该令牌调用实际的API。就是这样!

用例 #2

再次,我们必须进行两次API调用,这次我们需要同时获取两个API结果。如果我们只得到一个结果,那么我们无法在UI中显示它,也无法设置RecyclerView Adapter。

kt 复制代码
lifecycleScope.launch {
    //viewModel.secondApiCall()
    val result = firstApiCall()
    val result2 = secondApiCall()
    Log.d(TAG, "$result and $result2")
}

// Assume you have some suspend functions for API calls
suspend fun firstApiCall(): String {
    // Perform API call 1
    delay(2000) // Simulating a delay for demonstration
    return "I am first call"
}

suspend fun secondApiCall(): String {
    // Perform API call 2
    delay(2000) // Simulating a delay for demonstration
    return "I am second call"
}

就这样?并不完全是。因为它们将按顺序运行,也就是同步运行,所以完成这两个调用将需要4秒钟。

现在我们没有任何依赖关系,那么为什么要浪费时间呢?

让我们看看最终优化的代码!

kotlin 复制代码
lifecycleScope.launch {
    val result = async { firstApiCall() }
    val result2 = async { secondApiCall() }

    Log.d(TAG, "${result.await()} and ${result2.await()}")
}

现在你已经节省了2秒钟。请记住,这是每个Android开发者面试都会遇到的一个非常常见的问题。即使他们不问,你也可以提供这些示例来展示你的知识和专业能力。

感谢您的阅读!您可以关注我获取更多信息。

如果您想知道我在哪里,可以查看我的个人资料中的关于部分。

相关推荐
Kapaseker26 分钟前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 小时前
Andorid Google 登录接入文档
android
黄林晴3 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab15 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿18 小时前
Android MediaPlayer 笔记
android
Jony_18 小时前
Android 启动优化方案
android
阿巴斯甜19 小时前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇19 小时前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android
_小马快跑_1 天前
Kotlin | 从SparseArray、ArrayMap的set操作符看类型检查的不同
android