Android笔记(十八):面向Compose组件结合Retrofit2和Rxjava3实现网络访问

一、Retrofit2

Square公司推出的Retrofit2库(https://square.github.io/retrofit/),改变了网络访问的方式。它实现了网络请求的封装。Retrofit库采用回调处理方式,使得通过接口提交请求和相应的参数的配置,就可以获得对应的响应,并可以将响应获得的数据解析成特定的数据格式,例如将JSON数据解析成对象。
Retrofit访问网络资源的流程:
在这里插入图片描述

二、RxJava3

RxJava3(https://github.com/ReactiveX/RxJava)是响应式编程(Reactive Extensions)的java实现,它基于观察者模式的实现了异步编程接口。RxJava库通过使用可观察的序列来组成异步和基于事件的程序。
在这里插入图片描述

Observable可观察

即是一个主题,可以表示任何对象,它可以从数据源中获得数据或者其他的状态值。Observable对象发出数据流。只要有观察者开始接受,Observable就会提供数据,发出数据流。可观察者可以有多个订阅者。
在RxJava3中常见的可观察流如下表所示:

说明
io.reactivex.rxjava3.core.Flowable0…N流,支持响应式流和背压按照onSubscribe onNext (onError 或onComplete)属性执行,其中onNext可以执行多次,onError和onComplete是互斥的。
io.reactivex.rxjava3.core.Observable0…N流,不支持背压按照onSubscribe onNext (onError或onComplete)的顺序执行,onNext可以执行多次,onError与onComplete是互斥的。

Operator操作符

承担了对 Observable 可观察对象发出的事件进行修改和变换。每个Operator操作实际上是一个方法/函数,Observable对象作为输入参数,对于Observable对象发射的每一项数据,它会将在Operator方法/函数中应用这些数据,然后将处理结果以Observable对象形式返回。因此返回的是另外一个Observable对象。这个Observable对象可以继续向后发射或结束。

操作符Operator可以有若干个,形式如下:

dataSource.operator1()
.operator2()
.operator3()

这些操作符之间构成了上下流的关系。

Observer观察者

Observer观察者订阅可观察Observable对象的序列数据,并对可观察对象的每一项做出反应。观察者负责处理事件,它是事件的消费者。每当关联的Observable发出数据时,通知观察者。观察者一个接一个地处理数据。

背压策略

由于可观察者(Observable)和观察者(Observer)是在不同线程中分别实现发送数据和接受数据。由于不同线程中处理的时间伴随着问题的复杂度,会导致二者处理数据的速度出现不同。如果被观察者对象发射的数据的速度远远快于观察者对象处理数据的速度的话,会将数据放入到缓存暂存或者直接放弃这些数据。这两种方法的处理都有不妥之处。因此,需要制定“背压(Back Pressure)”策略,来解决二者在异步场景下,被观察者发射数据和观察者处理数据速度不一致的问题。因此,通常所说的背压是在异步环境下,控制流速的一种策略。常见的背压策略方式如下表所示:

背压策略说明
MISSING表示通过 create 方法创建的 Flowable 没有指定背压策略,不会对通过 OnNext 发射的数据做缓存或丢弃处理,下游必须处理操作符
ERROR发生背压,会发送MissingBackpressureException信号,以免下游不能消费继续。
BUFFER发生背压,会缓存数据,直至下游消化数据完成
DROP发生背压,会如果下游不能继续消费数据,将最近发射的值丢弃

三、网络访问处理实例

假设已经有网络资源 http://127.0.0.1:5000/json/students.json(也可以写成:http://localhost:5000/json/students.json),访问的内容如下所示:
在这里插入图片描述
在下面的例子中,将结合Retrofit2+RxJava3+Compose组件实现对上述资源的访问,并以列表的方式显示。运行结果类似下图:
在这里插入图片描述

1.AndroidManifest.xml配置网络访问

要访问网络需要设置互联网的访问权限,以及在应用中设置明文访问许可:

<uses-permission android:name="android.permission.INTERNET" />
<application
    android:usesCleartextTraffic="true" ...>
</application>

2.增加依赖

在项目模块的build.gradle.kt中增加如下依赖:

//retrofit框架
implementation (“com.squareup.retrofit2:retrofit:2.9.0”)
implementation (“com.squareup.retrofit2:converter-gson:2.9.0”)

//增加RxJava库的依赖
implementation (“io.reactivex.rxjava3:rxjava:3.1.5”)

//增加在Android对RxJava库的支持
implementation(“io.reactivex.rxjava3:rxandroid:3.0.2”)

//增加Retrofit支持RxJava3的CallAdapter
implementation(“com.squareup.retrofit2:adapter-rxjava3:2.9.0”)

implementation(“androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1”)

也可以根据最新的版本重新调整版本号。

3.定义实体类

data class Student(val id:String,
val name:String,
val gender:String,
val age:Int)

4.定义网络访问

(1)定义网络服务访问接口

interface StudentService{
    @GET("students.json")
    fun getStudents(): Flowable<List<Student>>
}

表示访问students.json资源获取一个RxJava3的Flowable可观察者对象。这个可观察者对象封装了包含学生记录的列表。

(2)定义网络服务创建类

object StudentServiceCreator{
    private val urlStr="http://10.0.2.2:5000/json/"

    private val retrofit = Retrofit.Builder()
        .baseUrl(urlStr)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
        .build()

    fun <T> createService(serviceClass:Class<T>):T = retrofit.create(serviceClass)
}

Web服务器是本地服务器,由于移动模拟器的127.0.0.1已经被占用,因此要在移动端访问本地服务器,可以通过10.0.2.2来访问。
定义Retrofit对象,并在该对象中设置了解析JSON数据的转换对象和并发处理的适配器。

5.定义定义视图模型

定义视图模型,调用的网络访问处理的相关类,获取网络资源。

class StudentViewModel: ViewModel() {
    private val students:SnapshotStateList<Student> = mutableStateListOf()
    private val creator  = StudentServiceCreator.createService(StudentService::class.java)
    fun doNetwork(urlStr:String){
        creator.getStudents()
               .observeOn(AndroidSchedulers.mainThread())
               .subscribe{it:List<Student>->
                    if(students.isEmpty()){
                        students.addAll(it)
                    }
               }
    }
    fun getData() = students
}

6.定义界面

(1)定义列表的显示学生记录单项的可组合函数

@Composable
fun StudentItemCard(student: Student){
    Card(modifier = Modifier
        .fillMaxWidth()
        .wrapContentHeight()
        .padding(5.dp),
        elevation = CardDefaults.cardElevation(defaultElevation = 5.dp),
        colors = CardDefaults.cardColors(
            containerColor = Color.Blue,
            contentColor = Color.White)){
        Column(modifier= Modifier
            .fillMaxWidth()
            .wrapContentHeight()
            .padding(5.dp)){
            Text(text = "${student.id}",fontSize = 24.sp)

            Row(modifier = Modifier.padding(15.dp)){
                Text(text = "${student.name}",fontSize = 24.sp)
                Spacer(modifier = Modifier.padding(5.dp))

                Text(text = "${student.gender}",fontSize = 24.sp)
                Spacer(modifier = Modifier.padding(5.dp))

                Text(text = "${student.age}",fontSize = 24.sp)
            }
        }
    }
}

(2)定义学生记录的列表

@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(stuVM: StudentViewModel = viewModel()){
    var students = stuVM.getData()
    val displayState = remember{ mutableStateOf(false) }

    Scaffold(floatingActionButton = {
        FloatingActionButton(onClick = {
            displayState.value = true
            //访问网络资源
            stuVM.doNetwork("http://10.0.2.2:5000/json/students.json")
            //获取学生记录
            students = stuVM.getData()
        }) {
            Icon(Icons.Filled.Refresh,contentDescription = null)
        }
    }){
        Column(horizontalAlignment = Alignment.CenterHorizontally){
            Text(modifier = Modifier.fillMaxWidth(),
                text = "学生记录列表",
                textAlign = TextAlign.Center,
                fontSize = 28.sp)
            if(displayState.value){
                LazyColumn{
                    items(students){it: Student ->
                        StudentItemCard(student = it)
                    }
                }
            }
        }
    }
}

7.定义主活动MainActivity

在主活动中调用界面

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Ch09_DemoTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    MainScreen()
                 }
            }
        }
    }
}

参考文献

陈轶 第8章 Android网络应用《Android移动应用开发(微课版)》P258-P293 清华大学出版社

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3 - Electron BrowserWindow对象 关于窗口

优雅的打开应用~ 当加载缓慢&#xff0c;打开应用的一瞬间会出现白屏&#xff0c;以下方法可以解决 const mainWindow new BrowserWindow({ show: false }) mainWindow.once(ready-to-show, () > {mainWindow.show() }) 设置背景颜色 const win new BrowserWindow({ b…

高德地图画线,适用于在地图上画出各种道路

addPolyline() {let AMap this.AMaplet polyline new AMap.Polyline({// map: this.map,// polyline 路径path: [new AMap.LngLat("119.368904", "30.913423"),new AMap.LngLat("119.382122", "30.901176"),],strokeColor: #F3D930,…

Windows下配置最新ChromeDriver

1、问题 在使用代码调用谷歌浏览器时会出错&#xff1a; from selenium import webdriver driver webdriver.Chrome() SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 114 Current browser versi…

低噪声 256 细分微步进电机驱动MS35776

产品简述 MS35776 是一款高精度、低噪声的两相步进电机驱动芯 片。芯片集成了快速模式与静音模式来满足高速与低速下的不 同应用。芯片内置功率 MOSFET &#xff0c;长时间工作平均电流可以达 到 1.4A &#xff0c;峰值电流 2A 。芯片集成了欠压保护、过流保护、短 地…

java中实现定时给微信群中发送每日天气情况

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 实现效果 这个功能&#xff0c;适用于做私域的朋友&#xff0c;下面是效果&#xff0c;大家可以参考一下&#xff1b; &#x1f534;&#x1f7e0;&#x1f7e1; 大家好&#xff01;我是…

【工具使用-有道云笔记】如何在有道云笔记中插入目录

一&#xff0c;简介 本文主要介绍如何在有道云笔记中插入目录&#xff0c;方便后续笔记的查看&#xff0c;供参考。 二&#xff0c;具体步骤 分为两个步骤&#xff1a;1&#xff0c;设置标题格式&#xff1b;2&#xff0c;插入标题。非常简单~ 2.1 设置标题格式 鼠标停在标…

【算法与数据结构】455、LeetCode分发饼干

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;因为大饼干可以满足大胃口的孩子也必然可以满足小胃口的孩子&#xff0c;如果要尽可能的满足孩子的胃口…

【LeetCode刷题笔记】数学

50. Pow(x, n) 解题思路: 1. 绝对值 + 快速幂 + 迭代 ,由于题目 n 可能是 系统最小值 ,因此使用 n 的 绝对值 。 如果 n 是 系统最小值 ,先让

使用Log4j与log4j2配置mybatisplus打印sql日志

环境&#xff1a;项目非完全spring项目&#xff0c;没有spring的配置文件。执行sql时老是不打印sql语句。因此进行修改&#xff0c;过程比较坎坷&#xff0c;记录一下。 我尝试使用log4j和log4j2进行配置 最终把这两种全部配置记录上 Log4j配置 如果项目用的是log4j需要进行配置…

Linux——权限

个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C语言小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 一、 Linux下用户的分类 Linux下有两种用户&#xff1a; 1. root&#xff08;超级管理员用户…

【重点】【前缀树】208.实现Trie(前缀树)

题目 前缀树介绍&#xff1a;https://blog.csdn.net/DeveloperFire/article/details/128861092 什么是前缀树 在计算机科学中&#xff0c;trie&#xff0c;又称前缀树或字典树&#xff0c;是一种有序树&#xff0c;用于保存关联数组&#xff0c;其中的键通常是字符串。与二叉查…

Python 列表推导式:简洁、高效的数据操作艺术

文章目录 Python 列表推导式&#xff1a;简洁、高效的数据操作艺术1. 列表推导式&#xff1a;语法糖的力量2. 过滤元素&#xff1a;带条件的列表推导式3. 复杂的数据结构&#xff1a;嵌套的列表推导式4. 数据变形&#xff1a;带表达式的列表推导式5. 推广至其他数据结构&#x…

LearnDash LMS ProPanel在线学习系统课程创作者的分析工具

点击阅读LearnDash LMS ProPanel在线学习系统课程创作者的分析工具原文 LearnDash LMS ProPanel在线学习系统课程创作者的分析工具通过整合报告和作业管理来增强您的 LearnDash 管理体验&#xff0c;使您能够发送特定于课程的通信&#xff0c;并显示课程的实时活动&#xff01…

堆与二叉树(上)

本篇主要讲的是一些概念&#xff0c;推论和堆的实现&#xff08;核心在堆的实现这一块&#xff09; 涉及到的一些结论&#xff0c;证明放到最后&#xff0c;可以选择跳过&#xff0c;知识点过多&#xff0c;当复习一用差不多&#xff0c;如果是刚学这一块的&#xff0c;建议打…

shell实现折线图

生成 100 行数据到文件 file.txt for ((i1; i<100; i));doif [ ${i} -lt 10 ];thennum$(( (RANDOM % 5) 10 i ))elsenum$(( (RANDOM % 5) 10 15 ))fiecho ${num} done 通过文件 file.txt 生成折线图 #!/bin/bash# 指定文件名&#xff0c;该文件必须为数字 file./file.…

Redis最实用的基础入门数据结构和常用指令使用教程

1.单线程redis操作为什么那么快&#xff1f; 一方面&#xff0c;Redis 的大部分操作在内存上完成&#xff0c;再加上它采用了高效的数据结构&#xff0c;例如哈希表和跳表&#xff0c;这是它实现高性能的一个重要原因。另一方面&#xff0c;就是 Redis 采用了多路复用机制&…

patchless amsi学习(中)

DR7 DR7被称为“调试控制寄存器”&#xff0c;允许对每个硬件断点进行精细控制。其中&#xff0c;前8位控制是否启用了特定的硬件断点。偶数位&#xff08;0、2、4、6&#xff09;称为L0-L3&#xff0c;在本地启用了断点&#xff0c;这意味着仅在当前任务中检测到断点异常时才…

配置Nginx解决跨域问题

Nginx 中将前端请求中的所有以 “/apiUrl” 开头的路径代理到 http://192.12.200.101:9813 例如&#xff1a; /apiUrl/login > http://192.12.200.101:9813/login 配置nginx环境 进入Nginx 的配置文件编辑界面: sudo nano /etc/nginx/conf.d/default.conf开始编辑 defaul…

7.实现任务的rebalance

1.设计 1.1 背景 系统启动后&#xff0c;所有任务都在被执行&#xff0c;如果这时某个节点宕机&#xff0c;那它负责的任务就不能执行了&#xff0c;这对有稳定性要求的任务是不能接受的&#xff0c;所以系统要实现rebalance的功能。 1.2 设计 下面是Job分配与执行的业务点…

使用案例总结Vlookup函数的30种用法

1 基础用法 =VLOOKUP(A12,B$1:D$8,3,0) 2 批量查找 =VLOOKUP(A11:A13,A2:C8,3,0) 3 模糊查找 =VLOOKUP("*"&D2&"*",A:B,2,0) 4 模糊查找2 =VLOOKUP(D10&"??",A:B,2,0) 5 模糊查找3 =
最新文章