ども、木村です。本業はデータサイエンティスト、副業でアプリ開発をしています。
本記事は、FlutterにおけるProviderの使い方を解説します。
- Providerがわからない方
- Providerを使って状態管理をしたい方
今回のソースコードは以下で公開されています。
Providerとは?
ProviderはFlutterで状態管理をしたいときに使用するライブラリです。
通常、Flutterで状態管理をしたい場合、StatefulWidget
と State
を使用して状態管理を行います。
そもそもStatefulWidget
についてわからない方は、少々理解が難しいと思うので以下の図解をご覧ください。
上記の通りStatefulWidget
と State
は1:1で紐づくため、State
の情報を複数の画面で利用したい場合利用することができません。
そのため、画面が多ければ多いほど同じような冗長なソースを実装しなければならなくなり、保守性が非常に悪くなります。
そこでProviderが大きな役割を果たします。
Providerを使えば親Widget
で取得した内容を子Widgetに受け渡すことができます。
これにより一つのステート情報を複数の画面で使用できるようになります。
そして何よりソースコードが非常にシンプルになります。
- Providerとは、Flutterで状態管理をしたいときに使用するライブラリ
- Providerを使うと一つのステート情報を複数の画面で使用できるようになる
Providerの使い方
今回はFlutterの初期プロジェクトがStatefulWidget
を使ったカウンターアプリになっていますので、こちらをProviderに変更する実装をして理解を深めていきたいと思います。
既存プロジェクトとの変更点を比較したい場合は、以下のGitHubのコミット差分を参照ください。
プロジェクトの作成
以下のコマンドで初期プロジェクトを作成します。
今回は「provider_demo」という名前でプロジェクトを作成します。
flutter create provider_demo
Providerの導入
pubspec.yamlにProvider導入の処理を追記しましょう。
dependencies:
provider: ^6.0.2
追記したら以下のコマンドでライブラリを導入します。
flutter pub get
Providerの実装
状態管理する対象を実装する
今回状態管理の対象となるのは、何回ユーザーにボタンを押したのかのカウンターの情報になります。
そして同じファイルにユーザーがボタンを押下したらカウンターの変数に+1する処理も実装します。
今回は、CountProvider.dartというファイルを新規で作成します。
import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';
class CountProvider with ChangeNotifier {
// 今回状態管理をする変数
int counter = 0;
//状態を変化させる処理(ボタンを押した時に実行される処理)
void incrementCounter() {
counter++;
notifyListeners();
}
}
上記ソースに出てくる重要な点を整理します。
with ChangeNotifier
変数の状態に変化があれば参照しているwidgetに画面再描画の通知を送ります。
notifyListeners();
一連の処理が終わったことをwidgetに伝え、画面再描画の通知を送ります。
Providerで管理しているステート情報を参照する
次にステート情報を参照してみましょう。
main.dartを以下のように書き換えてください。
import 'package:flutter/material.dart';
import 'package:provider_demo/CountProvider.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<CountProvider>(
create: (context) => CountProvider(),
),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
));
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CountProvider countProvider =
Provider.of<CountProvider>(context, listen: true);
return Scaffold(
appBar: AppBar(
title: Text('Flutter Demo Home Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
countProvider.counter.toString(),
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: countProvider.incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
重要な処理
MultiProvider(
providers: [
ChangeNotifierProvider<CountProvider>(
create: (context) => CountProvider(),
),
],
child: MaterialApp(
上記の処理で、子ウィジェットへ指定したステート情報への参照を許可しています。
一点注意するべきことは、親widgetが許可されたステート情報のみ子widgetは情報を参照できるため、必ず親ウィジェットでこちらの処理を実装してください。
final CountProvider countProvider =
Provider.of<CountProvider>(context, listen: true);
参照したい子widgetでこちらの処理を実装することで、Providerのデータを受け取ることができます。
countProvider.counter.toString(),
counterはCountProvider.dartで定義したカウント情報の変数名ですね。
このように記載すれば個別のステート情報を参照することが可能です。
onPressed: countProvider.incrementCounter,
ボタンが押されたときはCountProvider.dartで定義したincrementCounterメソッドの処理がよばれて、ステート情報であるcounterが+1される処理を実行しています。
まとめ:Providerを使って保守性をあげよう!
今回はFlutterにおけるProviderの使い方を解説しました。
Providerを使えばコードの保守性が上がるので大変おすすめです。
ぜひこの機会に習得してみてください。
最新のFlutterの勉強方法 まとめ
Flutterを入門から実践レベルまで一通り学習できる方法をまとめました。