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

news2024/12/30 2:23:29

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

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

协程问题

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

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中会发生什么?

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呢?想要知道答案,请自行运行代码看看结果。

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调用的结果。

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调用的示例。
好的,我们来看一些真实的代码。

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。

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秒钟。

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

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

lifecycleScope.launch {
    val result = async { firstApiCall() }
    val result2 = async { secondApiCall() }

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

现在你已经节省了2秒钟。请记住,这是每个Android开发者面试都会遇到的一个非常常见的问题。即使他们不问,你也可以提供这些示例来展示你的知识和专业能力。
感谢您的阅读!您可以关注我获取更多信息。
如果您想知道我在哪里,可以查看我的个人资料中的关于部分。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1634035.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AD21技巧[更加便捷的DRC检查][把线框转成Keep-Out Layer板框]

AD10用了好久,之所以换到AD21并不是因为AD10功能不够强,而且因为别人用高版本设计的软件到我这里竟然打不开了,这个是我不能够接受的,所以开始使用AD21,使用之后发现AD21好多使用习惯和AD10有很大的区别! 更加便捷的DRC检查 本文摘录于&#xff1a;https://www.cnblogs.com/U…

[Android14] SystemUI的启动

1. 什么是System UI SystemUI是Android系统级应用&#xff0c;负责反馈系统及应用状态并与用户保持大量的交互。业务主要涉及的组成部分包括状态栏(Status Bar)&#xff0c;通知栏(Notification Panel)&#xff0c;锁屏(Keyguard)&#xff0c;控制中心(Quick Setting)&#xff…

基于H.264的RTP打包中的组合封包以及分片封包结构图简介及抓包分析

H.264视频流的RTP封装类型分析&#xff1a; 前言&#xff1a; NULL Hearder简介(结构如下)&#xff1a; ---------------|0|1|2|3|4|5|6|7|--------|F|NRI| Type |--------------- F&#xff1a;forbidden_zero_bit&#xff0c; 占1位&#xff0c;在 H.264 规范中规定了这…

RustGUI学习(iced)之小部件(四):如何使用单选框radio部件?

前言 本专栏是学习Rust的GUI库iced的合集&#xff0c;将介绍iced涉及的各个小部件分别介绍&#xff0c;最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个&#xff0c;目前处于发展中&#xff08;即版本可能会改变&#xff09;&#xff0c;本专栏基于版本0.12.1. 概述…

【酱浦菌-爬虫技术细节】解决学术堂爬虫翻页(下一页)问题

首先我们通过css选择器获取页码信息&#xff0c;这里的css选择器&#xff0c;选择的是含有a标签的所有li标签&#xff0c;代码如下&#xff1a; li html_web.css(div.pd_c_xslb_left_fenye ul li>a) for li in li:li_url li.css(a::attr(href)).get()li_num li.css(a::t…

基于FPGA的数字信号处理(6)--如何确定Verilog表达式的符号

前言 尽管signed语法的使用能带来很多便利&#xff0c;但同时也给表达式的符号确定带来了更多的不确定性。比如一个有符号数和一个无符号数的加法/乘法结果是有符号数还是无符号数&#xff1f;一个有符号数和一个无符号数的比较结果是有符号数还是无符号数&#xff1f;等等。接…

IOT病毒分析

前言&#xff1a; 最近审计报警日志&#xff0c;发现了一个IOT病毒&#xff0c;利用的是CVE-2023-1389漏洞扫描tplink&#xff0c;进行攻击&#xff0c;有点意思&#xff0c;拿出来分析下。 发现&#xff1a; 查看流量日志&#xff0c;发现了一个有问题的访问&#xff1a; 访…

【架构】后端项目如何分层及分层领域模型简化

文章目录 一. 如何分层1. 阿里规范2. 具体案例分析 二. 分层领域模型的转换1. 阿里规范2. 模型种类简化分析 三. 小结 本文描述后端项目中如何进行分层&#xff0c;以及分层领域模型简化 一. 如何分层 1. 阿里规范 阿里的编码规范中约束分层逻辑如下: 开放接口层&#xff1a…

CSS实现各种优惠券效果

一、左半圆效果 <style style"text/css">.coupon {width: 240px;height: 100px;margin-top: 15px;background-color: #ff6347;-webkit-mask: radial-gradient(circle at left center, transparent 20px, red 20px); } </style><div class"coupon…

摩根大通推出创新工具 FlowMind,引领金融自动化新变革

近日&#xff0c;摩根大通人工智能研究部推出了一款极具创新性的工具——FlowMind&#xff0c;为金融行业带来了全新的工作模式和效率提升。 FlowMind 能够自动化金融工作流程&#xff0c;在信贷审批、风险评估、合规监测等重要任务中发挥着关键作用。它利用 GPT 自动生成工作…

张鸣独到政治观,规矩与自信新解

张鸣独解规矩与自信&#xff0c;社政新影响揭秘。张鸣独到政治观&#xff0c;规矩与自信新解在当今社会政治的大背景下&#xff0c;学者张鸣的每一次公开演讲无疑都是一次思想的盛宴。最近&#xff0c;他就当前的社会政治问题提出了自己独特的观点&#xff0c;特别是他对规矩和…

【网络原理】UDP协议 | UDP报文格式 | 校验和 | UDP的特点 | 应用层的自定义格式

文章目录 一、UDP协议1.UDP的传输流程发送方接收方 2.UDP协议报文格式&#xff1a;长度受限校验和如何校验&#xff1a;CRC算法&#xff1a;循环冗余算法md5算法&#xff1a; 2.UDP的特点 二、开发中常见的自定义格式1.xml&#xff08;古老&#xff09;2.json&#xff08;最流行…

头歌:Spark任务提交

第1关&#xff1a;spark-submit提交 任务描述 相关知识 spark-submit参数 计算圆周率 编程要求 测试说明 任务描述 本关任务&#xff1a;学会将程序提交到集群上执行。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.了解spark-submit的参数。2.学会提交Spar…

双目深度估计原理立体视觉

双目深度估计原理&立体视觉 0. 写在前面1. 双目估计的大致步骤2. 理想双目系统的深度估计公式推导3. 双目标定公式推导4. 极线校正理论推导 0. 写在前面 双目深度估计是通过两个相机的对同一个点的视差来得到给该点的深度。 标准系统的双目深度估计的公式推导需要满足:1)两…

按键的软件消抖

1.当出现物理情况比如单片机不小心摔了会发生灯亮的情况&#xff0c;所以我们得增加个延迟函数 2.这个错误是缺少头文件#include <intrins.h> 3. #include "reg52.h" #include <intrins.h>sbit key2 P2^0; sbit key1 P2^1; sbit ledone P3^7;voi…

稳扎稳打 部署丝滑 开源即时通讯(IM)项目OpenIM源码部署流程(linux windows mac)

背景 OpenIM包含多个关键组件&#xff0c;每个都是系统功能必不可少的一部分。具体来说&#xff0c;MongoDB 用于持久化存储&#xff1b;Redis 用作缓存&#xff1b;Kafka 用于消息队列&#xff1b;Zookeeper 用于服务发现&#xff1b;Minio 用于对象存储。这些组件的众多可能会…

用OpenCV先去除边框线,以提升OCR准确率

在OpenCV的魔力下&#xff0c;我们如魔法师般巧妙地抹去表格的边框线&#xff0c;让文字如诗如画地跃然纸上。 首先&#xff0c;我们挥动魔杖&#xff0c;将五彩斑斓的图像转化为单一的灰度世界&#xff0c;如同将一幅绚丽的油画化为水墨画&#xff0c;通过cv2.cvtColor()函数的…

【多级缓存】多级缓存OpenResty,Canal,nginx本地缓存

多级缓存 安装OpenRestyOpenResty入门OpenResty获取请求参数OpenResty向tomcat服务器发送请求 在nginx与tomcat端之间添加redis缓存Redis本地缓存缓存同步缓存同步策略基于Canal的异步通知安装Canal Canal客户端 安装OpenResty OpenResty是一个基于 Nginx的高性能 Web 平台&am…

[iOS]使用CocoaPods发布私有库

1.创建私有 Spec 仓库 首先&#xff0c;需要一个私有的 Git 仓库来存放你的 Podspec 文件&#xff0c;这个仓库用于索引你所有的私有 Pods。 在 GitHub 或其他 Git 服务上创建一个新的私有仓库&#xff0c;例如&#xff0c;名为 PrivatePodSpecs。克隆这个仓库到本地&#xf…

使用STM32CubeMX对STM32F4进行串口配置

目录 1. 配置1.1 Pin脚1.2 RCC开启外部晶振1.3 时钟1.4 串口配置 2. 代码2.1 默认生成代码2.1 开启串口中断函数2.3 接收中断2.4 接收回调函数2.5 增加Printf 的使用 1. 配置 1.1 Pin脚 1.2 RCC开启外部晶振 1.3 时钟 外部使用8MHz晶振 开启内部16MHz晶振 使用锁相环 开启最高…