Pagingを使った画面でスクロールが異常にカクカクしたときに起きていたこと

こんにちは、 id:numanuma08 です。最近調査、修正したPagingを使った画面でスクロールが重たくなり操作不能になるバグとその対策を紹介します。

当該画面は次のようにNestedScrollView内部に2つのRecyclerViewが配置されていました。

この状態でPagingを使うとページネーションされたすべてのデータを読み込み、表示しようとしてしまいます。そのためRecyclerViewの再描画が大量に発生して、スクロールが重たくなる不具合が発生していました。

NestedScrollView内に配置されたRecyclerViewは内部に表示するコンテンツの量に応じてView自体の高さが決定されます。そして、Pagingは一番最後の要素が描画されると次のページの要素を取得しに行きます。この2つの動作が組み合わさると、ページネーションしているのに画面を開いた瞬間ページのいちばん最後までデータを取得して表示を試みてしまいます。その結果、アプリのスクロール動作が遅くなります。

どうすればいいのか

ConcatAdapterを使って単一のRecyclerViewで画面を構成するといいでしょう。

developer.android.com

NestedScrollViewも利用せず、RecyclerViewのみで画面全体を構成します。ConcatAdapterはコンストラクタやプロパティからアダプター自体を追加可能です。複数RecyclerViewを使って画面を構成していた場合、2つ以上のRecyclerView.Adapterが存在するためそれらをのリストをConcatAdapterにセットすればOKです。

val usersAdapter = UsersAdapter()
val classesAdapter = ClassesAdapter()
val adapter = ConcatAdapter(
  usersAdapter, classesAdapter
)
binding.recyclerView.adapter = adapter

データの更新は元となったアダプターに対して行います。

observe(viewModel.users) {
  usersAdapter.submitList(it)
}

まとめ

複数のRecyclerViewをNestedScrollView内に配置したときにPagingの挙動がおかしくなる事例と対策を紹介しました。ページネーションを使った画面で異常にスクロールにもたつきがある報告が上がってきたら、このあたりを調査してみると良いかもしれません。