SingleChildScrollViewではなくSliverListを使ったらパフォーマンスが劇的に変わった件
今までSingleChildScrollView
を使ってPDFを表示していたが、大きなファイルだとメモリ不足でアプリが落ちる問題が報告されていた。
SingleChildScrollView
では、childの中身がすべて描画されるので、ListView.builder
を使うと良いらしい。
ただし、複数のPDFファイルを連続して表示する機能がある都合上、それぞれのPDFファイルごとにListView
を作る必要がある。
つまり、ListView
の中に複数のListView
があるという形なので、中のListView
のサイズが指定されないとエラーが出る。
これを修正するためにshrinkWrap: true
にすることができるが、そうすると、結局中のウィジェットがすべて構築されてしまうとのこと。
なお、shrinkWrapを使わずに、ListViewのサイズを指定してみたが、こうした場合も中のウィジェットがすべて構築されてしまうっぽい(パフォーマンスに変化がなかった)。
SingleChildScrollView
やListView.builder
, Sliver
のパフォーマンスの比較については、以下の記事がわかりやすい。
ということで、Sliver
を使うことに。
(実は以前使おうとしたのだが、その際うまくできなかったので一旦諦めていた)
全体のListView.builder
をCustomScrollView
にして、itemCount
やitemBuilder
がslivers
となる。
CustomScrollView(
//
slivers: List.generate(
_list.length,
(index) {
return _pdfView(index),
}
),
)
slivers
の中は、その直下がsliver
関係のWidgetとなる必要がある。
PDF読込中にCircularProgressIndicator
を表示するようにしているが、これについてはSliverToBoxAdapter
で囲う。
SliverToBoxAdapter(
child: const Center(child: CircularProgressIndicator()),
)
実際にそれぞれのPDFファイルを表示する部分は、SliverList
を使う。
SliverList(
delegate: SliverChildBuilderDelegate(
(context, pageIndex) {
//
},
childCount: length,
),
)
これによりパフォーマンスがかなり改善した。
実際にDev ToolsのPerformance viewを見てみると、前は8fpsとかしか出てなかったのが、40fpsを余裕で超えるようになった。
ページをジャンプした際にはページが完全に表示されるまで若干の時間がかかるが、1秒もないくらいだったので、十分許容範囲内だと感じた。