恢复 RecyclerView 的滚动位置

恢复 RecyclerView 的滚动位置

您可能在开发过程中遇到过这种情况,在 Activity/Fragment 被重新创建后,RecyclerView 丢失了它之前保有的滚动位置信息。通常这种情况发生的原因是由于异步加载 Adapter 数据,且数据在 RecyclerView 需要进行布局的时候尚未加载完成,导致 RecyclerView 无法恢复到之前的滚动位置。

从  1.2.0-alpha02 版本开始,Jetpack RecyclerView 提供了一个新的 API,可以让 Adapter  在数据加载完成之前阻塞布局行为 ,从而避免丢失滚动位置信息。接下来我们会介绍如何使用这个新的 API,以及它的工作原理。

恢复至原有滚动位置

有好几种方法可以用来恢复 RecyclerView 至正确的滚动位置,您可能已经在实际项目中用到了这些方法。其中最好的一种方法是将数据提前缓存在内存、ViewModel 或 Repository 中,然后确保在第一次布局传入之前,将缓存的数据设置到 Adapter 中去。如果根据您的项目实际情况无法采用这种方法,那也可以使用其他的方法,只是要么比较复杂 (比如避免在 RecyclerView 中设置 Adapter,但这样又有可能导致像 header 等 item 的显示问题),要么会导致 LayoutManager.onRestoreInstanceState API 被滥用。

recyclerview:1.2.0-alpha02 版本中提供的解决方案是引入一个新的 Adapter 方法,来允许您设置它的状态恢复策略 (通过枚举类型 StateRestorationPolicy)。它有三个选项:

  • ALLOW — 默认状态,会在下一次布局完成时立即恢复 RecyclerView 状态;
  • PREVENT_WHEN_EMPTY — 仅当 adapter 不为空 (即 adapter.getItemCount() > 0) 的时候,才恢复 RecyclerView 的状态。如果您是异步加载数据,RecyclerView 会等待数据加载完毕之后,才对状态进行恢复。如果在 Adapter 中有一些默认的 item,比如 header 或是 load progress indicator,那您应该使用 PREVENT 选项,除非是通过 ConcatAdapter 添加默认的 item,了解更多详细信息,请查阅《使用 ConcatAdapter 顺序连接其他 Adapter》。ConcatAdapter 会等待所有的 adapter 全部准备就绪后,才进行状态的恢复;
  • PREVENT — 所有的状态恢复都会等到您设置了 ALLOW 或者 PREVENT_WHEN_EMPTY 选项,才会得到执行。

通过如下示例代码可设置 adapter 的状态恢复策略:

adapter.stateRestorationPolicy = PREVENT_WHEN_EMPTY

通过这篇短小精悍的文章您可以了解到关于 RecyclerView 的延迟状态恢复 (lazy state restoration) 功能。赶快开始使用吧!

版权声明

禁止一切形式的转载-禁止商用-禁止衍生 申请授权

脉脉不得语
脉脉不得语
Zhengzhou Website
Android Developer | https://androiddevtools.cn and https://androidweekly.io Funder | GDG Zhengzhou Funder & Ex Organizer | http://Toast.show(∞) Podcast Host

你已经成功订阅到 Android 开发技术周报
太棒了!接下来,完成检验以获得全部访问权限 Android 开发技术周报
欢迎回来!你已经成功登录了。
Unable to sign you in. Please try again.
成功!您的帐户已完全激活,您现在可以访问所有内容。
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.
🍗