Provider — 2019年にRemi RousseletがInheritedWidgetのラッパーとして作成したFlutter向け状態管理パッケージです。Providerは、props drillingなしでウィジェットツリーの下位にデータを渡す問題を解決します。どのウィジェットもcontext.read<T>()またはcontext.watch<T>()を介して状態にアクセスできます。pub.devによると、Providerは25,000以上のいいねを持つFlutterで最も人気のある状態管理マネージャーです。
重要ポイント
Provider — InheritedWidgetの上に構築された、Flutterの状態管理と依存性注入のためのパッケージです。Providerはウィジェットツリーにオブジェクト(状態、サービス、リポジトリ)を提供し、データが変更されると自動的にUIを再構築します。InheritedWidgetを直接使用するのとは異なり、Providerはすべてのボイラープレートを排除します。InheritedWidgetのサブクラスを作成したり、静的なof()メソッドを設定したり、ネストを管理する必要はありません。
ProviderはGoogleがFlutterで推奨する公式の状態管理方法です(Flutter Team、2019〜2023年)。このパッケージはFlutter Ecosystemの一部であり、Flutterチームによってメンテナンスされています。リリース時、Providerはグローバル変数とInheritedWidgetの代替として提案されました。コンストラクターを介さずにどこからでも任意のオブジェクトにアクセスできます。
Flutter Community Survey 2025によると、ProviderはFlutterアプリケーションの72%で使用されています。人気の主な理由は、最小限の学習コスト、ChangeNotifierの組み込みサポート、他のアーキテクチャ(MVVM、BLoC)との互換性、外部依存関係がないことです。
ChangeNotifier — Listenerパターンを実装したFlutterの組み込みクラスです。ChangeNotifierはnotifyListeners()を呼び出して、サブスクライバーに変更を通知します。Providerのコンテキストでは、ChangeNotifierが状態のメインクラスとなります。ChangeNotifierを拡張するクラスを作成し、データ変更後にnotifyListeners()を呼び出すフィールドとメソッドを持ちます。
class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void reset() {
_count = 0;
notifyListeners();
}
}notifyListenersのルール: データを完全に変更した後に呼び出します。メソッドの途中ではなく最後に呼び出します。メソッドが複数の変更を実行する場合は、各変更後ではなく、すべての変更後に1回だけnotifyListeners()を呼び出します。これにより、1つの論理ステップでの複数の再描画を防ぎます。バッチ更新の場合は、setStateのようなパターンとともにnotifyListenersを使用します。
ChangeNotifierの代替: ValueNotifier — 単一の値用(プリミティブに適しています)、StateNotifier — state_notifierパッケージから(単独で使用されることはめったにありません)。ほとんどのProviderソリューションは、組み込みサポートとシンプルさからChangeNotifierを使用しています。
Consumer — ChangeNotifierをサブスクライブし、notifyListeners()が呼び出されるたびに再構築するウィジェットです。Consumerは、context、model、childの3つのパラメーターを持つビルダー関数を受け取ります。Child — モデルに依存せず、Consumerによって再構築されないウィジェットです。これは最適化です。Consumerに静的ウィジェット(アイコン、データのないテキスト)が含まれている場合、それはchildを介して渡され、再作成されません。
Consumer<CounterProvider>(
builder: (context, provider, child) => Column(
children: [
child!, // 再構築されない
Text('${provider.count}'),
ElevatedButton(
onPressed: () => provider.increment(),
child: Icon(Icons.add),
),
],
),
child: Text('カウンター:'),
)context.watch — ProviderをサブスクライブするためのBuildContextの拡張メソッドです。モデルを返し、現在のウィジェットをその変更にサブスクライブします。context.read — サブスクリプションなしのアクセス(onPressedハンドラー、initState、dispose用)。context.select — 他のフィールドが変更されても再構築せずに、モデルの特定のフィールドをサブスクライブします。Selectは10以上のフィールドを持つ複雑なモデルに最も効率的なオプションです。
Consumer、watch、selectを使用するタイミング: Consumer — 最適化のために子ウィジェットが必要な場合。watch — 単純な読み取りのためにbuildメソッド内で使用。select — モデルに複数のフィールドがあるが、ウィジェットが1つだけに依存する場合。Providerはウィジェットが破棄されると自動的にサブスクリプションを解除し、メモリリークを防ぎます。
MultiProvider — ネストなしで複数のProviderを登録するためのウィジェットです。Provider → Provider → Providerの5レベルのツリーの代わりに、MultiProviderはプロバイダーのリストを受け取ります。後続の各Providerは、コンストラクターを介して前のProviderを使用できます。MultiProviderはアプリケーションのルートレベルを整理する標準的な方法です。
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CartProvider()),
ChangeNotifierProvider(create: (_) => AuthProvider()),
ProxyProvider<AuthProvider, OrderProvider>(
update: (_, auth, __) => OrderProvider(auth.userId),
),
],
child: MaterialApp(home: HomePage()),
)ProxyProvider — 別のProviderに依存するProviderです。ProxyProviderは他のProviderから値を取得し、それらを自身のオブジェクトに渡します。たとえば、OrderProviderはAuthProviderに依存します(userIdが必要)。AuthProviderが変更されると、ProxyProviderは新しいuserIdでOrderProviderを自動的に再作成します。ChangeNotifierProxyProvider — ChangeNotifier向けのProxyProviderのバージョンです。
StreamProviderとFutureProvider: StreamProviderはStream(Firebase、WebSocket)をサブスクライブし、新しいイベントごとにConsumerを更新します。FutureProvider — 非同期初期化用:Futureを実行し、ローディングを表示してから、結果をウィジェットに渡します。どちらも手動のサブスクリプション管理なしで一般的なタスクを解決します。
Providerのテストは、テスト値を含むMultiProviderでウィジェットをラップして行います。テストに実際のAPIやデータベースは必要ありません。Providerはモックされたオブジェクトに置き換えられます。providerパッケージはテストの分離のためのProviderScopeを提供します。各テストは独立して独自のProviderツリーを作成します。
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Counter increments on button tap',
(tester) async {
await tester.pumpWidget(
ChangeNotifierProvider(
create: (_) => CounterProvider(),
child: CounterScreen(),
),
);
await tester.tap(find.byKey(Key('increment')));
await tester.pump();
expect(find.text('1'), findsOneWidget);
},
);
}MockProvider: APIに依存するProviderを持つウィジェットをテストするには、スタブサブクラスを作成するか、mockito / mocktailを使用します。Providerには特別なモックツールは必要ありません。ChangeNotifierを拡張する任意のオブジェクトを、実際のサービスを呼び出さずにcreateを介して渡すことができます。簡単に置き換えられるように、インターフェース(抽象クラス)を介してProviderをプログラミングします。
ProviderのパフォーマンスはInheritedWidgetに基づいています。Providerが変更されると、context.watchまたはConsumerを介してサブスクライブされたすべてのウィジェットが再構築されます。不必要な再描画を防ぐには、context.select(特定のフィールドへのサブスクリプション)、Consumerのchildパラメーター、および静的ウィジェットにはconstを使用します。Providerは変更をサブスクライブしていないブランチを再構築しません。
| メソッド | サブスクリプション | 再構築 | 使用例 |
|---|---|---|---|
| context.watch | モデル全体 | 任意の変更 | シンプルなウィジェット |
| Consumer | モデル全体 | 任意の変更 | child最適化あり |
| context.select | 特定のフィールド | フィールド変更時のみ | 複雑なモデル |
| context.read | なし | なし | イベントハンドラー |
制限事項: Providerは(BLoCのような)イベントレベルでのビジネスロジックの分離をサポートしていません。すべての変更はChangeNotifierメソッドの直接呼び出しを通じて行われ、制御不能な変更の連鎖を引き起こす可能性があります。複雑なシナリオ(複数の非同期操作、複雑なバリデーション)では、ProviderはBLoCやRiverpodに劣ります。
Providerからの移行: Providerは他のパッケージと簡単に組み合わせることができます。Riverpodに移行するには、ChangeNotifierProvider.adaptiveを使用します。これは、既存のChangeNotifierを書き換えずにRiverpodで使用できるようにするアダプターです。BLoCの場合 — BlocProviderをProviderツリー内に配置して、ChangeNotifierを徐々にBlocに置き換えることができます。
よくある質問
Provider — ChangeNotifierを使用した依存性注入のためのInheritedWidgetのラッパーです。BLoC — ロジック分離のためのEvent + Streamを使用したアーキテクチャパターンです。Providerは学習が容易で、BLoCはコードをより厳密に構造化します。Providerは小規模なアプリケーションやUI状態に適しており、BLoCは複雑なビジネスロジックに適しています。Flutter Community 2025によると、両方は同じプロジェクトで一緒に使用されることがよくあります。
ChangeNotifierProvider — ChangeNotifierインスタンス用のProviderの一種です。createを介してオブジェクトを作成し、子孫に提供し、notifyListenersが呼び出されたときにConsumerを再構築します。ChangeNotifierProviderはツリーから削除されると、ChangeNotifierで自動的にdisposeを呼び出します。作成方法は3つあります。ChangeNotifierProvider.value(既存のオブジェクト用)、ChangeNotifierProvider(遅延作成用)、ChangeNotifierProvider.create(明示的な遅延作成用)です。
context.watchの代わりにcontext.selectを使用します。選択したフィールドが変更された場合のみウィジェットが再構築されます。大きなChangeNotifierを複数の小さなものに分割します(1モデル=1責任)。静的パーツにはConsumer childを使用します。リストには、キーを使用してListView.builderを使用します。Provider DevTools(Flutter Inspector)は、どのウィジェットが再構築されているかとその理由を表示します。
はい。Provider(ChangeNotifierなし) — 不変オブジェクト(リポジトリ、APIクライアント、設定)を注入するため。ValueListenableProvider — ValueNotifier用。StreamProvider — Stream(Firebase、WebSocket)用。FutureProvider — Future(起動時の設定読み込み)用。ProxyProvider — 他のProviderに依存するProvider用。ChangeNotifierは、UI更新を伴う可変状態にのみ必要です。
ProviderNotFoundException — ウィジェットツリーの上位で宣言されていないProviderを取得しようとすると発生する実行時例外です。一般的な原因:Providerが読み取ろうとしているウィジェットよりも下位で宣言されている。Providerがあるルートで宣言され、別のルートで読み取られている。タイプの入力ミス。解決策:Providerをツリーの上位に移動するか、グローバルな依存関係のためにMaterialAppレベルでMultiProviderを使用します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。