Android官方架构组件Paging-Ex_列表状态的响应式管理(1)

文章探讨了Android官方架构组件Paging在处理列表状态管理时的挑战,提出利用本地缓存作为数据源,避免频繁刷新和内存状态维护。作者介绍了如何通过Room数据库管理和下拉刷新操作的实现,强调了系统化学习的重要性。
摘要由CSDN通过智能技术生成

反思|Android 列表分页组件Paging的设计与实现:系统概述
反思|Android 列表分页组件Paging的设计与实现:架构设计与原理解析

以上两篇文章将对Paging分页组件进行了系统性的概述,笔者强烈建议 读者将以上两篇文章作为学习 Paging 阅读优先级 最高 的学习资料,所有其它的Paging中文博客阅读优先级都应该靠后

本文及相关引申阅读:

Android官方架构组件Paging:分页库的设计美学
Android官方架构组件Paging-Ex:为分页列表添加Header和Footer
Android官方架构组件Paging-Ex:列表状态的响应式管理

概述

PagingGoogle在2018年I/O大会上推出的适用于Android原生开发的分页库,随着越来越多的开发者着手使用Paging,越来越多的问题暴露出来,最直接的一个问题是:

如何管理列表额外的状态?

这样的需求随处可见,比如 侧滑删除为评论点赞 等等:

本文将阐述:如何管理Paging分页列表的 状态,为何这样设计,以及设计的过程。

列表的状态问题

和市面上其它热门的分页库相比,Paging最大的亮点在于其 将列表分页加载的逻辑作为回调函数封装入 DataSource,开发者在配置完成后,无需通过代码手动控制分页的加载,列表会 自动加载 下一页数据并展示。

这种便利意味着开发者不需要自己持有 数据源 ,大多数时候这使得开发流程更加便利,但总有偶然,比如这样一个界面:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这种需求屡见不鲜,其本质是,列表本身展示服务端返回的列表数据之外,还需要 本地控制额外的状态

什么叫 额外的状态 ? 我们先用简单的一张图展示没有额外状态的情形,这时,列表的所有UI元素都从服务端获取:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我们将上文Gif中的点赞效果也通过一张图表示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

读者可能还未认识到两种业务场景之间的差异性:对于列表的初始化来讲,所有UI元素都被服务端返回的数据渲染,每条评论是否已经被点赞,服务端都通过Comment进行了描述。

需要注意的是,在某一刻,用户发现某个评论非常有趣,因此他选择对该评论进行了点赞的操作。

在业务代码中,我们需要向服务端POST一个点赞的请求,服务端返回了一个200的成功码,但问题来了,接下来我们 如何让列表中的那条评论状态发生变化(即点赞的icon由灰色变成绿色高亮,已告知用户点赞成功)?

这就引发了文章最开始的那个问题,当列表的状态发生了变更,如何管理并更新列表?

方案1:再次刷新请求接口

最简单的方案是再次请求API,每当列表状态发生了变更,重新拉取评论列表,服务端返回的最新数据中,该评论自然已经被点赞了(即列表正确进行了更新)。

读者应该清楚,该方案实际并不可行,原因有二:

  • 成本太高:某些操作对于用户来说,应该是非常 轻量级 的(比如点赞),他们甚至希望这些操作能够 立即被响应 在UI上 ,而请求API并刷新列表这一个过程太重了,即使不考虑服务器的负担,对于用户来说,UI的刷新需要数秒的等待也是非常糟糕的体验。
  • 不符合逻辑:我们更需要注意的是,Paging是一个分页列表,而刷新请求行为对于分页列表来说,是一个不符合产品预期的行为(比如,我的点赞操作是针对第5页的某个评论执行的,产品的设计不可能允许每次点赞都重置为列表的第一页数据,这意味着极度糟糕的用户体验)。

现在我们理解了 每当列表状态发生了变更就刷新接口 并非良策,因为这种通过 远程重新拉取数据源 更新UI的方式成本太高了。

方案2:额外维护一个状态的列表

大概思路是在内存中为RecyclerView维护一个额外的List,用于一一映射对应positionItem状态:

class CommentPagedAdapter(
private val likedList: ArrayList
)

通过在内存中维护这样一个List,的确可以实现需求,但读者需要认识到的是,Paging分页库本身最大的优点便是 随着列表的滚动自动加载分页数据,每次分页的行为开发者并不需要手动配置,并通过调用类似notifyItemRangeInserted()的方法更新UI。

很显然,每当分页数据获取后,开发者依然需要手动维护这个额外状态的List——方案2和选择使用Paging的初衷背道而驰,因此它并非最优先考虑的方案。

库本身设计的问题?

现在问题是,既不能通过 服务端 作为数据源,也不能在 内存中 额外维护一个状态的列表, 读者难免会质疑Paging库本身设计的问题。

我该如何控制列表额外的状态(包括修改、增加或者删除)?

事实上该问题已经在Github的这个 issue 中进行了讨论,Google的工程师的回复是:

从技术的角度而言 ,我们可以创建一个允许部分更改数据源的API,但之后我们需要记录这些改动并在主线程上重新传递给列表。这种方法的问题在于,如果你有一个已停止的RecyclerView(也就是后堆栈),它将不会(也不应该)接收任何更新,因此PagedList将保留这个可能很长的数据列表并重新应用于主线程上的每个观察者。

这使问题变得非常复杂,这就是我们使用单个列表的原因。

显然,Paging考虑到了更多,和市面上 什么都能做 的框架相比,它 敢于收紧开发者API的调用权限,在开发者们发挥更多奇思妙想之前,将其紧紧束缚到了可控制的范围之内,这也是笔者非常推崇Paging的原因之一。

那么我们该如何处理我们的业务?此时引入一个新的角色似乎是一个不错的选择,那就是 持久层(即缓存)。

通过架构解决业务问题

综上所述,对于分页列表的状态管理问题,需要做到的是:

  • 1.将一个单独的List交给Paging去进行分页加载并渲染(不应在内存中手动维护一个额外状态的列表);
  • 2.不应该每次都通过重的操作刷新数据源(比如网络请求刷新接口)。

因此,我们需要一个 中间件 进行业务的调度——在需要刷新整个数据源的时候(比如用户的下拉刷新操作),从服务端拉取数据;在不需要繁重的操作时(比如用户针对某个评论进行点赞),仅仅需要针对单个数据源进行简单的修改。

这已经不单单是业务业务的问题,并且涉及到了项目本身的架构,接下来, 持久层 (即本地缓存)闪亮登场。

1.用持久层作为唯一的数据源

Android平台的数据库框架有很多种,本文以官方的架构组件Room为例。

为什么要为项目的架构额外添加一个持久层?事实上,随着项目体系的日益庞大,数据库是终究需要添加进入项目中的,因此,在设计项目的架构之前,提前将数据库的框架配置进来是一个不错的选择——未雨绸缪总不是坏事。

以列表的渲染为例,让我们来看看项目之前的结构:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回到本文,对于Paging来讲,我们并无法直接获取数据源,因此对于列表状态的管理,我们需要额外的角色帮助,那就是本地的持久化缓存。

让我们看看添加了持久层之后的结构:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加了缓存之后,每当我们尝试初始化一个分页列表,框架会从服务器拉取数据,之后数据被存储到了Room中。

请注意!Paging原生提供了对Room数据库框架的支持,因此它总是可以第一时间响应到数据库中数据的变化,并自动渲染在UI上

现在,我们将 请求服务器API数据的渲染 两者通过持久层进行了隔离,对于RecyclerView来说,持久层是唯一的数据源,即:

列表只反应了数据库的变更。

现在列表的显示和服务端的请求已经 完全无关 了,读者也许会有这样的疑问——这样做的好处是什么?

2.列表状态的管理

现在我们回到文中最初的问题,如何管理列表的状态?

对于一个拥有复杂状态的分页列表,无论是 服务端 作为数据源,还是在 内存中 额外维护一个状态列表,都不是很好的选择;而现在我们加入了Room,并作为列表唯一的数据源,局势发生了怎样微妙的变化呢?

让我们来看看加入了持久层之后,下拉刷新的逻辑发生了怎样的变化:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 1.下拉刷新意味着我们需要重置数据,因此我们手动清除了数据库内对应表中的数据;
  • 2.当表中数据被清空时,Paging会自动响应到数据的变化,因为没有了数据,所以Paging会自动向服务器请求数据;
  • 3.数据返回后,会再次将数据存储到数据库中;
  • 4.这时Paging会再次响应到数据库的变化,并将最新的数据渲染到UI上。

看起来逻辑复杂了很多,实际上读者需要明确的是,步骤2、3、4都是我们作为开发者在初始化Paging时就配置好的,因此如果用户需要刷新页面,只需要进行第一步的操作即可,即类似这样的一行代码:

// 刷新操作,仅需清除表内的列表数据
fun swipeRefresh() {
// 运行一个事务
db.runInTransaction {
// 清除列表数据
db.getDao().clearDataList()
}
}

小福利:

在当下这个碎片化信息环境的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021大厂最新Android面试真题解析

Android大厂面试真题解析

各个模块学习视频:如数据结构与算法

算法与数据结构资料图

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。
一线互联网架构师

这份体系学习笔记,适应人群:**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。第三,到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。如果你有需要,我这里恰好有为什么,不来领取!说不定能改变你现在的状态呢!点赞+评论即可获得!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

到真正的技术提升。**

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值