Android笔记(二十二):Paging3分页加载库结合Compose的实现网络单一数据源访问

Paging3 组件是谷歌公司推出的分页加载库。个人认为Paging3库是非常强大,但是学习难点比较大的一个库。Paging3组件可用于加载和显示来自本地存储或网络中更大的数据集中的数据页面。此方法可让移动应用更高效地利用网络带宽和系统资源。在具体实现上,Paging3与前面的版本完全不同。

一、依赖库的配置

    val paging_version = "3.2.0"implementation("androidx.paging:paging-runtime:$paging_version")implementation("androidx.paging:paging-compose:$paging_version")// optional - RxJava3 supportimplementation("androidx.paging:paging-rxjava3:$paging_version")//支持viewmodelimplementation ("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1")//增加RxJava库的依赖implementation("io.reactivex.rxjava3:rxjava:3.0.7")implementation("io.reactivex.rxjava3:rxandroid:3.0.0")//增加Retrofit库的支持implementation("com.squareup.retrofit2:retrofit:2.9.0")implementation("com.squareup.retrofit2:converter-gson:2.9.0")//增加Retrofit支持RxJava3的CallAdapterimplementation("com.squareup.retrofit2:adapter-rxjava3:2.9.0")

二、Paging3的架构

Paging3的架构分为三层,如下图所示:
在这里插入图片描述

1.代码库层Repository

PagingSource:定义数据源(来自网络或来自本地数据库,已经从该数据源检索数据);
RemoteMediator:用来处理来自分层数据(例如:来自缓存的网络数据源)的分页

2.ViewModel视图模型层

Pager组件提供了一个公共 API,基于PagingSource 对象和 PagingConfig配置对象来构造在响应式流中公开的 PagingData 实例。
ViewModel 层连接到界面的组件是PagingDataPagingData 对象是用于存放分页数据快照的容器。它会查询PagingSource对象并存储结果。

3.界面层

界面层通过结合Compose组件的LazyColumn以列表方式显示分页加载的数据。

三、网络资源的介绍

为了更好地解释Paging3组件,笔者爬取了一些视频数据保存到本地MySQL数据库,并结合Python+Flaskj将MySQL数据库的保存的数据生成按照页面和每一页展示数据的个数生成对应json数据,通过这种方式获得网络资源。
在这里插入图片描述
这时可以通过浏览器浏览相关内容,类似下图所示:这里传递了两个参数 page表示第几页,size表示页面显示记录数。
在这里插入图片描述
上列展示的json数组包含了多个json对象,每个json对象的格式类似下列形式:

{"actors":"演员",
"directors":"导演",
"intro":"电影简介",
"poster":"http://localhost:5000/photo/s_ratio_poster/public/p2626067725.jpg",
"region":"地区",
"release":"发布年份",
"trailer_url":"https://localhost:5000/trailer/268661/#content",
"video_url":"https://localhost:5000/d04d3c0d2132a29410dceaeefa97e725/view/movie/M/402680661.mp4"}

当然,在具体实现时也可以考虑JavaEE + Tomcat来搭建后台应用。

四、实现Paging3的方式一:PagingSource单一数据源(网络)的处理

在这里,是通过访问单一网络数据源"http://127.0.0.1:5000/film.json?page=1&size=5"来获取分页数据,如上图所示。具体的架构如下图所示:
在这里插入图片描述

1.定义实体类Film

data class Film(
@SerializedName(“name”)
val name:String,
@SerializedName(“release”)
val release:String,
@SerializedName(“region”)
val region:String,
@SerializedName(“directors”)
val directors:String,
@SerializedName(“actors”)
val actors:String,
@SerializedName(“intro”)
val intro:String,
@SerializedName(“poster”)
val poster:String,
@SerializedName(“trailer_url”)
val trailer:String,
@SerializedName(“video_url”)
val video:String
)
在此处说明一下,@SerializedName表示对应json形式的单一film的数据。这样就可以在后续的处理中将请求的json数据根据json数据的关键字获取对应的值,利用这些值生成对应Film对象。

2.网络访问处理

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

interface FilmApiService {@GET("film.json")suspend fun getData(@Query("page") page:Int,@Query("size") size:Int):List<Film>
}

此处,page属性对应URL中的page表示页,size表示每一页的记录数;

(2)利用Retrofit构建网络服务

object RetrofitBuilder {private const val  BASE_URL = "http://10.0.2.2:5000/"private fun getRetrofit(): Retrofit {return Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build()}val apiService:FilmApiService =getRetrofit().create(FilmApiService::class.java)
}

3.定义代码层

(1)定义代码层要实现的操作接口

interface FilmRepository {/*** 获取指定page页面的信息* @param page Int* @return List<Film>*/suspend fun getFilms(page:Int,limit:Int = 5):List<Film>
}

4.P
(2)具体代码层的实现

class FilmRepositoryImp:FilmRepository {private val apiService: FilmApiService = RetrofitBuilder.apiServiceoverride suspend fun getFilms(page: Int,limit:Int): List<Film>= apiService.getData(page, limit)}

4.定义数据源

class FilmSource(private val filmRepository: FilmRepository): PagingSource<Int, Film>() {override suspend fun load(params: LoadParams<Int>):LoadResult<Int, Film> {return try{val currentPage = params.key ?:1Log.d("请求页面标记:","请求第${currentPage}页")val filmResponse = filmRepository.getFilms(currentPage)val prevKey = if(currentPage==1) null else currentPage-1val nextKey = if(filmResponse.isEmpty()) null else currentPage+1LoadResult.Page(data = filmResponse,prevKey = prevKey,nextKey = nextKey)}catch(e:Exception){if (e is IOException) {Log.d("测试错误数据", "-------连接失败")}Log.d("测试错误数据", "-------${e.message}")LoadResult.Error(throwable = e)}}override fun getRefreshKey(state: PagingState<Int, Film>): Int? {return state.anchorPosition}
}

5.定义视图模型层ViewModel

class MainViewModel: ViewModel() {private val filmRepository: FilmRepository = FilmRepositoryImp()fun getFilms(): Flow<PagingData<Film>> = Pager(PagingConfig(pageSize = 5)){FilmSource(filmRepository)}.flow
}

在上面的代码中配置每一页的记录数默认为5,在函数getFilms中获得一个协程流的数据封装了每页的记录。

6.结合Compose的LazyColumn定义界面层

(1)定义单独Film一行记录的界面内容

@Composable
fun FilmCard(film: Film?) {Card(modifier = Modifier.fillMaxSize().padding(2.dp),elevation = CardDefaults.cardElevation(5.dp),colors = CardDefaults.cardColors(containerColor = Color.Black)){Column{Row(modifier = Modifier.fillMaxSize()){AsyncImage(model = "${film?.poster}",contentDescription = "${film?.name}")Column{Text("${film?.name}",fontSize = 18.sp,color = Color.White)Text("导演:${film?.directors}",fontSize = 14.sp,color = Color.Green)Text("演员:${film?.actors}", fontSize = 14.sp,color = Color.White)}}Text("${film?.intro?.subSequence(0,50)} ...",fontSize = 14.sp,color=Color.Green)Row(horizontalArrangement = Arrangement.End,modifier = Modifier.fillMaxSize()){Text("More",fontSize=12.sp)IconButton(onClick ={}){Icon(imageVector = Icons.Default.MoreVert,tint=Color.Green,contentDescription = "更多...")}}}}
}

(2)定义列表

@Composable
fun FilmScreen(mainViewModel: MainViewModel) {val films:LazyPagingItems<Film> = mainViewModel.getFilms().collectAsLazyPagingItems()val TAG = "加载状态"Column(horizontalAlignment = Alignment.CenterHorizontally,modifier = Modifier.background(Color.White)){LazyColumn{items(films.itemCount){FilmCard(films[it])}}}
}

7.定义主活动MainActivity

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val mainViewModel:MainViewModel = viewModel()Ch11_DemoTheme {// A surface container using the 'background' color from the themeSurface(modifier = Modifier.fillMaxSize(),color = MaterialTheme.colorScheme.background) {FilmScreen(mainViewModel)}}}}
}

运行效果如下:
在这里插入图片描述

参考文献

Paging库概览
https://developer.android.google.cn/topic/libraries/architecture/paging/v3-overview?hl=zh-cn

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

根据文法求对应的语言

技巧&#xff1a;最后得到的是终结符组成的闭包 例题&#xff1a; 文法G[S]: S-->AB A-->aAb|ab B-->Bc|&#xff0c;求对应的语言 ①S-->(aAb|ab)(Bc|) ②我们可以观察到&#xff0c;无论A-->aAb还是A-->ab&#xff0c;都一定会同时出现ab,…

PiflowX组件-WriteToKafka

WriteToKafka组件 组件说明 将数据写入kafka。 计算引擎 flink 有界性 Streaming Append Mode 组件分组 kafka 端口 Inport&#xff1a;默认端口 outport&#xff1a;默认端口 组件属性 名称展示名称默认值允许值是否必填描述例子kafka_hostKAFKA_HOST“”无是逗号…

使用Halcon 采集图像并进行简单处理rgbl_to_gray/threshold/connection/fill_up

使用Halcon 采集图像并进行简单处理 文章目录 使用Halcon 采集图像并进行简单处理 下面介绍一个简单的采集图像的例子。在Halcon中利用图像采集接口&#xff0c;使用USB3.0相机实时拍摄图像。采集到图像后对图像进行简单的阀值分割处理&#xff0c;将有物体的区域标记出来。 &a…

抬头举手阅读YOLOV8NANO

首先用YOLOV8NANO得到PT模型&#xff0c;转换成ONNX,OPENCV调用&#xff0c;PYTHON,C,ANDROID都可以举手写字阅读YOLOV8NANO

基于Freeswitch实现的Volte网视频通知应用

现在运营商的Volte网络已经很好的支持视频通话了&#xff0c;因此在原来的电话语音通知的基础上&#xff0c;可以更进一步实现视频的通知&#xff0c;让用户有更好的体验&#xff0c;本文就从技术角度&#xff0c;基于Freeswitch来实现此类应用&#xff08;本文假设读者已对Fre…

Redis哨兵

1.哨兵介绍 1.1.为何需要哨兵&#xff1f; 为了解决master节点宕机问题&#xff0c;选举salve节点为新的master节点。 1.2.哨兵的作用 1.3.服务状态监控 1.4.选举新的master 1.5.如何实现故障转移 2.搭建哨兵集群 2.1.集群结构 这里我们搭建一个三节点形成的Sentinel集群&…

蓝桥杯-Excel地址[Java]

目录&#xff1a; 学习目标&#xff1a; 学习内容&#xff1a; 学习时间&#xff1a; 题目&#xff1a; 题目描述: 输入描述: 输出描述: 输入输出样例: 示例 1: 运行限制: 题解: 思路: 学习目标&#xff1a; 刷蓝桥杯题库日记 学习内容&#xff1a; 编号96题目Ex…

re:Invent 2023技术上新|Amazon DynamoDB与OpenSearch Service的Zero-ETL集成

Amazon DynamoDB 与 Amazon OpenSearch Service 的 Zero-ETL 集成已正式上线&#xff0c;该服务允许您通过自动复制和转换您的 DynamoDB 数据来搜索数据&#xff0c;而无需自定义代码或基础设施。这种 Zero-ETL 集成减少了运营负担和成本&#xff0c;使您能够专注于应用程序。这…

php获取访客IP、UA、操作系统、浏览器等信息

最近有个需求就是获取下本地的ip地址、网上搜索了相关的教程&#xff0c;总结一下分享给大家、有需要的小伙伴可以参考一下 一、简单的获取 User Agent 信息代码: echo $_SERVER[HTTP_USER_AGENT]; 二、获取访客操作系统信息: /** * 获取客户端操作系统信息,包括win10 * pa…

Adobe 设计精髓:创新的用户体验 | 开源日报 No.130

adobe/react-spectrum Stars: 10.1k License: Apache-2.0 React Spectrum Libraries 是一系列的库和工具&#xff0c;旨在帮助开发者构建适应性强、可访问性好且稳健的用户体验。 核心优势&#xff1a; 提供全面的可访问性和行为支持&#xff0c;符合 WAI-ARIA 编写实践&…

Transformer(seq2seq、self-attention)学习笔记

在self-attention 基础上记录一篇Transformer学习笔记 Transformer的网络结构EncoderDecoder 模型训练与评估 Transformer的网络结构 Transformer是一种seq2seq 模型。输入一个序列&#xff0c;经过encoder、decoder输出结果也是一个序列&#xff0c;输出序列的长度由模型决定…

redis cluster判断key属于那个分片。

一、判断阿里云 redis cluster&#xff0c;的key属于那个分片。 阿里云特有的命令info key 可以查看key属于那个slot&#xff0c;那个分片 命令行查看&#xff1a; xxxx:6379> info key xxxx_compressed_xxx slot:4941 node_index:9 xxxx:6379> cluster keyslot xxxx_…

基于 Webpack 插件体系的 Mock 服务

背景 在软件研发流程中&#xff0c;对于前后端分离的架构体系而言&#xff0c;为了能够更快速、高效的实现功能的开发&#xff0c;研发团队通常来说会在产品原型阶段对前后端联调的数据接口进行结构设计及约定&#xff0c;进而可以分别同步进行对应功能的实现&#xff0c;提升研…

WPF+Halcon 培训项目实战(8):WPF+Halcon初次开发

前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想换个工作。相关的教学视频来源于下方的Up主的提供的教程。这里只做笔记分享&#xff0c;想要源码或者教学视频可以和他联系一下。 相关链接 微软系列技术教程 WPF 年度公益课程 Halcon开发 CSD…

uniapp中uview组件库丰富的Calendar 日历用法

目录 基本使用 #日历模式 #单个日期模式 #多个日期模式 #日期范围模式 #自定义主题颜色 #自定义文案 #日期最大范围 #是否显示农历 #默认日期 基本使用 通过show绑定一个布尔变量用于打开或收起日历弹窗。通过mode参数指定选择日期模式&#xff0c;包含单选/多选/范围…

【JS笔记】JavaScript语法 《基础+重点》 知识内容,快速上手(二)

数组 什么是数组&#xff1f; 字面理解就是 数字的组合 其实不太准确&#xff0c;准确的来说数组是一个 数据的集合 也就是我们把一些数据放在一个盒子里面&#xff0c;按照顺序排好 [1, 2, 3, hello, true, false]这个东西就是一个数组&#xff0c;存储着一些数据的集合 …

复数值神经网络可能是深度学习的未来

一、说明 复数这种东西,在人的头脑中似乎抽象、似乎复杂,然而,对于计算机来说,一点也不抽象,不复杂,那么,将复数概念推广到神经网络会是什么结果呢?本篇介绍国外的一些同行的尝试实践,请我们注意观察他们的进展。

C语言 volatile关键字

volatile关键字介绍 volatile 是一个关键字&#xff0c;用于修饰变量&#xff0c;表示该变量是易变的&#xff0c;即可能在任何时候被意外地改变。在多线程编程中&#xff0c;当多个线程同时访问同一个变量时&#xff0c;由于线程之间的交互和优化&#xff0c;可能会导致变量的…

手机怎么下载python并安装,如何在手机上下载python

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;如何在手机上下载python 3.7版本&#xff0c;手机怎么下载python并安装&#xff0c;现在让我们一起来看看吧&#xff01; 如何在手机上下载python 应用市场内搜索下载下载Python在您开始之前&#xff0c;在你的计算机将…

Linux性能优化全景指南

Part1 Linux性能优化 1、性能优化性能指标 高并发和响应快对应着性能优化的两个核心指标&#xff1a;吞吐和延时 应用负载角度&#xff1a;直接影响了产品终端的用户体验系统资源角度&#xff1a;资源使用率、饱和度等 性能问题的本质就是系统资源已经到达瓶颈&#xff0c;但…