
您可能在開發(fā)過(guò)程中遇到過(guò)這種情況,在 Activity/Fragment 被重新創(chuàng)建后,RecyclerView 丟失了它之前保有的滾動(dòng)位置信息。通常這種情況發(fā)生的原因是由于異步加載 Adapter 數(shù)據(jù),且數(shù)據(jù)在 RecyclerView 需要進(jìn)行布局的時(shí)候尚未加載完成,導(dǎo)致 RecyclerView 無(wú)法恢復(fù)到之前的滾動(dòng)位置。
從 1.2.0-alpha02 版本開始,Jetpack RecyclerView 提供了一個(gè)新的 API,可以讓 Adapter 在數(shù)據(jù)加載完成之前阻塞布局行為 ,從而避免丟失滾動(dòng)位置信息。接下來(lái)我們會(huì)介紹如何使用這個(gè)新的 API,以及它的工作原理。
恢復(fù)至原有滾動(dòng)位置
有好幾種方法可以用來(lái)恢復(fù) RecyclerView 至正確的滾動(dòng)位置,您可能已經(jīng)在實(shí)際項(xiàng)目中用到了這些方法。其中最好的一種方法是將數(shù)據(jù)提前緩存在內(nèi)存、ViewModel 或 Repository 中,然后確保在第一次布局傳入之前,將緩存的數(shù)據(jù)設(shè)置到 Adapter 中去。如果根據(jù)您的項(xiàng)目實(shí)際情況無(wú)法采用這種方法,那也可以使用其他的方法,只是要么比較復(fù)雜 (比如避免在 RecyclerView 中設(shè)置 Adapter,但這樣又有可能導(dǎo)致像 header 等 item 的顯示問(wèn)題),要么會(huì)導(dǎo)致 LayoutManager.onRestoreInstanceState API 被濫用。
recyclerview:1.2.0-alpha02 版本中提供的解決方案是引入一個(gè)新的 Adapter 方法,來(lái)允許您設(shè)置它的狀態(tài)恢復(fù)策略 (通過(guò)枚舉類型 StateRestorationPolicy)。它有三個(gè)選項(xiàng):
- ALLOW — 默認(rèn)狀態(tài),會(huì)在下一次布局完成時(shí)立即恢復(fù) RecyclerView 狀態(tài);
- PREVENT_WHEN_EMPTY — 僅當(dāng) adapter 不為空 (即 adapter.getItemCount() > 0) 的時(shí)候,才恢復(fù) RecyclerView 的狀態(tài)。如果您是異步加載數(shù)據(jù),RecyclerView 會(huì)等待數(shù)據(jù)加載完畢之后,才對(duì)狀態(tài)進(jìn)行恢復(fù)。如果在 Adapter 中有一些默認(rèn)的 item,比如 header 或是 load progress indicator,那您應(yīng)該使用 PREVENT 選項(xiàng),除非是通過(guò) ConcatAdapter 添加默認(rèn)的 item,了解更多詳細(xì)信息,請(qǐng)查閱《使用 ConcatAdapter 順序連接其他 Adapter》。ConcatAdapter 會(huì)等待所有的 adapter 全部準(zhǔn)備就緒后,才進(jìn)行狀態(tài)的恢復(fù);
- PREVENT — 所有的狀態(tài)恢復(fù)都會(huì)等到您設(shè)置了 ALLOW 或者 PREVENT_WHEN_EMPTY 選項(xiàng),才會(huì)得到執(zhí)行。
通過(guò)如下示例代碼可設(shè)置 adapter 的狀態(tài)恢復(fù)策略:
adapter.stateRestorationPolicy = PREVENT_WHEN_EMPTY
通過(guò)這篇短小精悍的文章您可以了解到關(guān)于 RecyclerView 的延遲狀態(tài)恢復(fù) (lazy state restoration) 功能。趕快開始使用吧!