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.hqwc.cn/news/308532.html

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

相关文章

最新AI系统ChatGPT网站H5系统源码,支持AI绘画,GPT语音对话+ChatFile文档对话总结+DALL-E3文生图

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

【华为数据之道学习笔记】8-1 基于PDCA的数据质量管理框架

企业数据来源于多个不同的业务系统&#xff0c;数据流转、处理环节多&#xff0c;用“Garbage in Garbage out&#xff08;垃圾进&#xff0c;垃圾出&#xff09;”原则保证数据质量已成为数字化转型企业的共识。企业数据质量管理是一个系统性的工程&#xff0c;华为数据质量从…

Java核心技术卷接口的实现与继承多态知识梳理总结

Java核心技术卷接口的实现与继承多态知识梳理总结 接口的概念 在Java程序设计语言中&#xff0c;接口不是类&#xff0c;而是对希望符合这个接口的类的一组需求。 form&#xff1a; Java核心技术卷 I&#xff08;原书第11版&#xff09; 基础知识 by 凯 S.霍斯特曼 在Java中&a…

基于element-ui table组件的二次封装

文章目录 配置数据基础分析封装 el-table-column使用插槽强化结语 相信 element-ui 大家都有所耳闻&#xff0c;table 也是老朋友了&#xff0c;不过在使用它的时候大家是怎么使用的呢&#xff1f;是直接在官网上cv使用吗&#xff1f;这种方式&#xff0c;我相信写起来会有点小…

web前端开发html/css求职简介/个人简介小白网页设计

效果图展示&#xff1a; html界面展示&#xff1a; html/css代码&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.…

基于Python、Keras和OpenCV的实时人脸活体检测

你在互联网上找到的大多数人脸识别算法和研究论文都遭受照片攻击。这些方法在检测和识别来自网络摄像头的图像、视频和视频流中的人脸方面非常有效。然而&#xff0c;他们无法区分现实生活中的面孔和照片上的面孔。这种无法识别人脸的现象是由于这些算法在二维帧上工作。 现在…

VS2013中特殊操作

代码段管理器(查看代码补全快捷方式) 1.点击 工具 ->点击 代码片段管理器->看到 语言->选择 Visual C 2.可以点击下方添加 自定义一个属于自己的快捷代码补全方式 3.结果图&#xff1a; 设置自动换行与行号 1.点击 工具->点击 选项->找到 文本编辑器(然后点击)…

cleanmymac这个软件怎么样?值不值得下载

cleanmymac是我必装的mac端清理软件&#xff0c;界面简洁好看&#xff0c;完美适配mac系统&#xff0c;文件清理的速度、精度都比较优秀&#xff0c;还是比较不错的呢。cleanmymac作为一款第三方清洁应用程序&#xff0c;具有专业完整的清理功能&#xff0c;包括释放内存、一键…

Live800:客户体验策略是什么?企业如何制定客户体验策略?

客户体验策略是企业为了提升顾客对产品或服务的感知和满意度而采取的一系列措施和方法。它关注的是如何创造一个积极、愉悦和有价值的购买过程&#xff0c;从而建立长期的客户关系和忠诚度。客户体验策略是企业成功的关键之一&#xff0c;因为它能够帮助企业在竞争激烈的市场中…

如何像高级软件工程师一样使用vscode做开发

以一个真实的代码库为例&#xff0c;带您了解高级软件工程的关键原则是什么&#xff0c;以及如何充分利用vscode提供的各种特性来提高开发效率。您可以将学到的技巧和思想应用于任何项目。 视频地址&#xff1a; 如何像高级软件工程师一样使用vscode做开发 欢迎关注公众号&a…

JDK9及之后版本使用 jlink 生成定制化的 JRE

许多java软件的运行需要依赖jre&#xff0c;在 jdk8 之后&#xff0c;不再提供默认的 jre&#xff0c;后续如果项目中还是想用 jre 的形式发布软件&#xff0c;那么可以使用 jlink 工具生成 jre。 一、jlink 命令详解 jlink 二、查看jdk中包含的所有模块 如果在 jdk 安装文件夹…

从0到1浅析Redis服务器反弹Shell那些事

文章目录 前言Redis服务1.1 特点与应用1.2 安装与使用1.3 语法和配置1.4 未授权访问 反弹Shell2.1 Web服务写入Webshell2.2 Linux定时任务反弹shell2.3 /etc/profile.d->反弹shell2.4 写入ssh公钥登录服务器2.5 利用Redis主从复制RCE2.6 SSRF漏洞组合拳->RCE 总结 前言 …