Paging3简单理解

简介: Paging3简单理解

功能概览


  • Paging可以将数据在内存中缓存,从而高效利用系统资源
  • 内置重复的请求信息删除,从而高效利用网络
  • 可配置Recycleview适配器,从而在用户滚动到尾部时自动加载数据
  • 对Flow、Livedata、RxJava都可以支持
  • 内置错误处理功能,包括刷新和重试


架构分级


image.png


代码库层

PagingSource和RemoteMeditor是Paging的数据源,PagingSource可以从单个数据源获取数据,RemoteMeditor可以从混合数据源获取数据


ViewModel层

Pager 组件提供了一个公共 API,基于 PagingSource 对象和 PagingConfig 配置对象来构造在响应式流中公开的 PagingData 实例。

将 ViewModel 层连接到界面的组件是 PagingData。PagingData 对象是用于存放分页数据快照的容器。它会查询 PagingSource 对象并存储结果。

界面层中的主要 Paging 库组件是 PagingDataAdapter,它是一种处理分页数据的 RecyclerView 适配器。

此外,您也可以使用随附的 AsyncPagingDataDiffer 组件来构建自己的自定义适配器。


使用


依赖

dependencies {
  val paging_version = "3.0.1"
  implementation("androidx.paging:paging-runtime:$paging_version")
  // alternatively - without Android dependencies for tests
  testImplementation("androidx.paging:paging-common:$paging_version")
  // optional - RxJava2 support
  implementation("androidx.paging:paging-rxjava2:$paging_version")
  // optional - RxJava3 support
  implementation("androidx.paging:paging-rxjava3:$paging_version")
  // optional - Guava ListenableFuture support
  implementation("androidx.paging:paging-guava:$paging_version")
  // optional - Jetpack Compose integration
  implementation("androidx.paging:paging-compose:1.0.0-alpha12")
}
复制代码


基础使用

各个api的作用

使用Paging需要自定义几个类

PagingDataAdapter:自定义adapter

PagingSource<Int, Book>:自定义数据源,泛型第一个参数是查询数据的key,一般使用Int类型,其它类型亦可

DiffUtil.ItemCallback<Book>():自定义去重机制,内部有两个方法,分别是areItemsTheSame  : areContentsTheSame。其中areItemsTheSame用来判断两个item是否是相同的对象一般用来比对对象地址是否相同,areContentsTheSame一般用来比对两个对象内部的数据是否相同,比如你如果返回多个相同的字符串那有可能会被认为都是重复的。

Pager用来处理配置相关内容


简单使用Paging加载数据代码

适配器
class CustomPage1Adapter(differCallback: DiffUtil.ItemCallback<Book>) :
    PagingDataAdapter<Book, CustomPage1Holder>(differCallback) {
    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: CustomPage1Holder, position: Int) {
        holder.btn.text = "${getItem(position)?.name}:$position"
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomPage1Holder {
        return CustomPage1Holder(Button(parent.context))
    }
}
class CustomPage1Holder(val btn: Button) : RecyclerView.ViewHolder(btn) {
}
复制代码


PagingSource
class CustomPageSource : PagingSource<Int, Book>() {
    var index = 0
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Book> {
        val data = params.key.let { key ->
            if (key == null) {
                listOf(Book("安娜"))
            } else if (key > 10) {
                null
            } else {
                delay(300)
                listOf(
                    Book("安娜"),
                    Book("卡列尼亚"),
                    Book("百年孤独"),
                    Book("三体"),
                    Book("史记"),
                    Book("后汉书"),
                    Book("项羽本纪"),
                    Book("hello"),
                    Book("world"),
                    Book("教父")
                )
            }
        }
        logEE("当前加载页:${params.key}")
        return if (data == null || data.isEmpty()) {
            LoadResult.Error(NullPointerException("空指针"))
        } else {
            LoadResult.Page(
                data = data, prevKey = null, nextKey = ++index
            )
        }
    }
    override fun getRefreshKey(state: PagingState<Int, Book>): Int? {
        return null
    }
}
复制代码


DiffUtil.ItemCallback
object BookCompartor : DiffUtil.ItemCallback<Book>() {
    override fun areItemsTheSame(oldItem: Book, newItem: Book): Boolean {
        return oldItem.name == newItem.name
    }
    override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean {
        return oldItem == newItem
    }
}
复制代码


配置代码
val flow = Pager(
        PagingConfig(10)//设置每页数据为10条
    ) {
        CustomPageSource()//数据源
    }.flow.cachedIn(viewModelScope)//在ViewModel中缓存数据,这样做可避免配置更改的时候数据丢失
复制代码


初始化Paging方式
val recycle = findViewById<RecyclerView>(R.id.recycle1)
        val adapter = CustomPage1Adapter(BookCompartor)
        recycle.layoutManager = LinearLayoutManager(this)
        recycle.adapter = adapter
        lifecycleScope.launch {
            model.flow.collectLatest {
                adapter.submitData(it)//提交数据到适配器
            }
        }
复制代码


给Paging添加Footer

直接上代码


DataAdapter数据适配器

class DataAdapter :
    PagingDataAdapter<Bean, DataAdapter.FooterHeaderHolder>(diffCallback = object :
        DiffUtil.ItemCallback<Bean>() {
        override fun areItemsTheSame(oldItem: Bean, newItem: Bean): Boolean = oldItem ==newItem
        override fun areContentsTheSame(oldItem: Bean, newItem: Bean): Boolean =
            oldItem == newItem
    }) {
    override fun onBindViewHolder(holder: FooterHeaderHolder, position: Int) {
        holder.tv.text = "${getItem(position)?.des}"
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FooterHeaderHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_fh,parent,false)
        return FooterHeaderHolder(view)
    }
    inner class FooterHeaderHolder(view: View) : RecyclerView.ViewHolder(view) {
        val tv: TextView = view.findViewById(R.id.tv_item)
    }
}
复制代码


底部加载中的Footer

底部的Footer也是用适配器的方式实现,在初始化阶段会通过withLoadStateFooter方法适配到数据适配器DataAdapter

class LoadingFooterAdapter(val retry: () -> Unit) :
    LoadStateAdapter<LoadingFooterAdapter.FooterHolder>() {
    override fun onBindViewHolder(holder: FooterHolder, loadState: LoadState) {
        when (loadState) {
            is LoadState.Error -> {
                holder.itemView.visibility = View.GONE
            }
            is LoadState.Loading -> {
                holder.itemView.visibility = View.VISIBLE
            }
            is LoadState.NotLoading -> {
                holder.itemView.visibility = View.GONE
            }
        }
    }
    override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): FooterHolder {
        val view =
            LayoutInflater.from(parent.context).inflate(R.layout.item_footer_loading, parent, false)
        return FooterHolder(view)
    }
    inner class FooterHolder(view: View) : RecyclerView.ViewHolder(view) {
    }
}
复制代码


数据源Source

class FHPageSource : PagingSource<Int, Bean>() {
    override fun getRefreshKey(state: PagingState<Int, Bean>): Int? = null
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Bean> {
        val nextKey = params.key ?: 1
        return if (nextKey > 10) {
            logEE("加载异常")
            LoadResult.Error(IllegalArgumentException("不合法"))
        } else {
            delay(1000)
            logEE("加载数据")
            LoadResult.Page(
                listOf(
                    Bean("安娜:$nextKey"),
                    Bean("李白:$nextKey"),
                    Bean("安安安安卓:$nextKey"),
                    Bean("王维:$nextKey"),
                    Bean("杜甫:$nextKey"),
                    Bean("李贺:$nextKey")
                ), prevKey = null, nextKey = nextKey + 1
            )
        }
    }
}
复制代码


Pager配置

val flow = Pager(PagingConfig(10)) {
        FHPageSource()
    }.flow.cachedIn(viewModelScope)
复制代码


初始化代码

val recycle = findViewById<RecyclerView>(R.id.recycle_fh)
        recycle.layoutManager = LinearLayoutManager(this)
        val adapter = DataAdapter()
        recycle.adapter =  adapter.withLoadStateFooter(footer = LoadingFooterAdapter(){
            adapter.retry()
        })//这一句代码是关键
        lifecycleScope.launch {
            model.flow.collect {
                adapter.submitData(it)
            }
        }



相关文章
|
编译器 API 容器
Compose:从重组谈谈页面性能优化思路,狠狠优化一笔
Compose:从重组谈谈页面性能优化思路,狠狠优化一笔
1114 0
|
XML 前端开发 IDE
在 Compose 中使用 Jetpack 组件库
在 Compose 中使用 Jetpack 组件库
1390 0
|
算法 Java
Java实现文件搜索详解
文件搜索是计算机应用中的一个常见任务,它允许用户查找特定文件或目录,以便更轻松地管理文件系统中的内容。在Java中,您可以使用各种方法来实现文件搜索。本文将详细介绍如何使用Java编写文件搜索功能,以及一些相关的内容。
545 0
|
5月前
|
人工智能 资源调度 自然语言处理
AI agent指挥官 重塑智能体协作的新时代蓝图
随着 2026 年 AI 技术进入深度协作阶段,AI agent 指挥官成为连接智能体(AI Agents)执行层与业务价值层的核心枢纽。本文深入分析智能体协作的发展背景、技术栈演进、核心组件与架构模式,提出一种全新的 “协作智能体架构” 框架,以流程化、可执行的方式解释指挥官如何统筹规划、管理智能体、多模型服务与资源调度,从而实现高效、可控、可审计的智能体系统。
508 1
|
设计模式 安全 编译器
Kotlin 中的密封类:详解与应用
【8月更文挑战第31天】
1017 0
|
Android开发
40. 【Android教程】AsyncTask:异步任务
40. 【Android教程】AsyncTask:异步任务
604 2
|
人工智能 小程序 安全
Kimi 高效使用技巧,80%的人都不知道(上)
Kimi 高效使用技巧,80%的人都不知道
|
缓存 前端开发 Android开发
安卓现代化开发系列——从状态保存到SavedState
安卓现代化开发系列——从状态保存到SavedState
519 1
|
Android开发 Kotlin 容器
Jetpack-Compose 学习笔记(二)—— Compose 布局你学会了么?(上)
Jetpack-Compose 学习笔记(二)—— Compose 布局你学会了么?(上)
736 1