Flutterの状態管理手法のBLoCパターンを学習したのでアウトプットする。
重要な前提
**知識面についてはこちらの記事を読めばほぼ解決します。**私はQiita書き終わってから気づきました。
本記事が提供するもの
- サンプルを動かしながらBLoCパターンを学習する方法として、Getting Started with the BLoC Patternを紹介する。
これで終了なのだが、せっかくなので私が学んだことをアウトプットしてみる。
前提
- 現在BLoCパターンは、Flutterの状態管理手法として最適とは考えられていない。
- 実用ではProvider, RiverPod等を用いるのが主流であると思う。
- 状態管理手法の学習はInheritedWidget使用から始めるのがよいのだと思う。InheritedWidgetをラップしたのが前述のProviderである
- BLoCパターンを体系的に学習する際は本記事ではなく、こちらを参照するのがよい。
BLoCパターンについての私の理解
- BLoCパターンはWidget Treeとビジネスロジック(BLoC)をきれいに分離できてよい。
- 分離の仕組みを以下に記す。
BLoCとWidgetTreeの関係
- ボタンを押す等の操作時にWidgetからBLoCに情報を伝える
- BLoCがその情報をWidgetに伝える
- (情報を受け取ったWidgetがStreamBuilder等で表示を更新する)
出典: すめだブログ FlutterのBLoCパターンについて得た知見
BLoCの中身
- Sinkで情報を受取る
- Streamで情報を流す
出典: Getting Started with the BLoC Pattern
サンプル: 最もシンプルなBLoCパターン活用例
以上で説明したように、BLoCそのものは単純な仕組みである。最も単純なBLoC利用サンプルを見つけたので紹介する。
ただしアプリの構成が複雑になるとBLoCを利用する工夫が必要になってきて、そこが複雑になりうる。
BLoCProvider = BLoCパターンを利用する場合の工夫
上に述べたものが恐らくBLoCパターンの全貌であるが、Widget Treeの階層がある場合は、以下の問題に対処する必要がある。
配下のWidgetからBLoCを利用できるようにするため、以下の対応が必要になる。
- あるWidgetでBLoCを保持する
- 配下のWidgetからBLoCがアクセス可能にする
また、あるWidgetでBLoCを保持するため、以下の対応が必要になる。
- BLoCを保持するWidgetが破棄された際に、BloC内のstreamをcloseする
そこでBLoCProviderと呼ばれる仕組みが必要になる。
上述のシンプルな例はBloCを使うのは1階層のStatelessWidget内なので、ここで挙げた対応は不要であり、BLoCProviderは必要ない。
BLoCProvider
BLoCを使う配下の階層を持つ構成では、以下の処理をするような仕組みが必要になる。
- あるWidgetでBLoCを保持する
- 配下のWidgetからBLoCへのアクセスを可能にする
- BLoCを保持するWidgetが破棄された際に、BloC内のstreamをcloseする
チュートリアルではStatefulWidgetであるBlocProvider
クラスがそれを担っている。この BlocProvider
クラスは、以下の方法で問題に対応している。
- プロパティとしてBLoCを保持する
-
findAncestorWidgetOfExactType
で配下のWidgetからアクセス可能にする -
dispose()
内でStreamController
をclose()
する
dispose()
を利用するためにStatefulWidgetにしたというわけだ。
計算量O(N)の解決
上述の方法の問題点として、findAncestorWidgetOfExactType
の計算量がO(N)であることが挙げられる。これによってWidgetTreeの規模が大きくなるとパフォーマンスが悪くなるのだ。
これを解決して、BlocProviderにO(1)でアクセスするには、さらにInheritedWidgetを組み込んだ仕組みにするとよい。
そのためのライブラリとして bloc_provider
がある。
また、以下の用にProviderと併用する方法もあるようだ。
Flutter BLoC+Providerとマルチプロバイダーのサンプル(戻るボタンのフックで苦労した話)
まとめ
- BLoCパターンの本質は、この記事により最短で把握できる。
- BLoCパターンの実用はこのチュートリアルでサンプルを動かしながら把握できる。
- これに加えて、この記事やこのライブラリを参考に計算量の解決をするとよい。
さらにまとめ
- こちらの記事を読めば全部解決できることに気づいた。
- この記事にあるように、現在のスタンダードはBLoCではなくprovider + ChangeNotifierと考えてよいと思う。ただしこちらの詳しい解説は本稿の範囲外とする。