Provider解説

Flutterアプリ開発

【初心者向け】Flutter Providerパッケージの基本から応用まで

Flutter Providerとは?基本の理解から始めよう

この記事では、Providerの基本的な概念を紹介します。Flutterの「Provider」は、アプリケーション内の状態管理を簡単に行うためのパッケージです。

アプリケーションが大きくなると、データを効率よく管理し、異なるウィジェットにデータを共有する必要が出てきます。Providerは、このデータの提供者(Provider)と消費者(Consumer)を明確に分け、ウィジェットツリー全体でデータを管理・共有しやすくします。

Zapp

Zapp

とりあえずFlutterを始めてみたいという場合、Zappというサービスを使うことをおすすめします。

オンライン上でFlutterのプログラムを書くことがきるエディターです。最初から基本的な環境構築がされているため、すぐにFlutterを始めることができます。

Zapp

Providerパッケージのセットアップ方法と基本設定

ここでは、Providerパッケージの導入手順と、プロジェクトにセットアップする際の基本的な設定方法を解説します。

パッケージを導入する方法は、主に以下の2つがあります。

A. コマンドでパッケージを追加する

$ flutter pub add provider

B. pubspec.yamlファイルにパッケージを追加する

dependencies:
    provider: ^6.12.0

パッケージの依存関係を追加したら、下記のコマンドでパッケージをインストールします。

$ flutter pub get

パッケージが追加できたら、ChangeNotifierProviderやStreamProviderを使って、アプリ全体で状態管理するプログラムを書いていきます。コード例を使用しながら解説していきます。

ChangeNotifierで簡単に状態管理を実装する方法

FlutterのChangeNotifierクラスを使うと、状態が変更された際にリスナー(消費者)に通知する仕組みを簡単に実装できます。

ここでは、ChangeNotifierを使ってデータの変更を管理し、それをProviderでウィジェットに提供する方法を紹介します。また、notifyListeners()メソッドを使用して、データが変更されたときにウィジェットをリビルドする流れを解説します。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(ChangeNotifierProvider(
      create: (_) => Counter(),
      child: MyApp(),
  ));
}

class Counter extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count += 1;
    notifyListeners();
  }
}

class MyApp extends StatelessWidget {
    const MyApp({super.key});

    @override
    Widget build(BuildContext context) {
        Counter counter = context.watch<Counter>();

        return MaterialApp(
            title: 'Sample App',
            theme: ThemeData(
                colorSchemeSeed: Colors.indigo,
                useMaterial3: true,
                brightness: Brightness.light,
            ),
            darkTheme: ThemeData(
                colorSchemeSeed: Colors.blue,
                useMaterial3: true,
                brightness: Brightness.dark,
            ),
            home: Scaffold(
                appBar: AppBar(
                    title: Text('Flutter Example App'),
                ),
                body: Center(
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                            const Text(
                                'You have pushed the button this many times:',
                            ),
                            Text(
                                '${counter.count}',
                                style: Theme.of(context).textTheme.headlineMedium,
                            ),
                        ],
                    ),
                ),
                floatingActionButton: FloatingActionButton(
                    onPressed: () => { counter.increment() },
                    tooltip: 'Increment',
                    child: const Icon(Icons.add),
                ),
            ),
            debugShowCheckedModeBanner: false,
        );
    }
}

実装すると以下の通りになります。

実装例

複数のProviderを組み合わせた応用テクニック

複雑なアプリケーションでは、複数のデータソースや状態を一度に管理する必要があります。

ここでは、MultiProviderやProxyProviderを使って、複数のProviderを組み合わせた高度な状態管理方法を紹介します。例えば、異なるProvider間で依存関係がある場合、それを効果的に管理するための実装例や、マルチレベルな状態管理をどのように行うかを具体的に解説します。

void main() {
    runApp(MultiProvider(
        providers: [
            ChangeNotifierProvider(create: (_) => Counter()),
            ChangeNotifierProvider(create: (_) => AdditionalProvider()),
        ],
        child: const MyApp()
    ));
}
ProxyProvider<UserService, GreetingService>(
    update: (
        BuildContext context,
        UserService userService,
        GreetingService greetingService
    ) => GreetingService(userService: userService),
)

void main() {
    runApp(ProxyProvider0<Result>(
        update: (context, result) {
            final a = Provider.of<A>(context);
            final b = Provider.of<B>(context);
            return update(context, a, b, result);
        }
    ))
}

開発効率を上げる!実践的なProviderの活用例

Providerを上手に活用することで、アプリのパフォーマンスを向上させることができます。例えば、SelectorやConsumerを適切に使うと、必要な部分のみリビルドすることができます。

状態の特定のプロパティにだけ依存するウィジェットを作成できます。これにより、変更が不要な部分のリビルドを避けられます。

Selectorの活用

Selectorを使って特定のプロパティに依存するUIのみリビルドし、余分なリビルドを減らすことができ、パフォーマンスを向上できます。

Selector<MyModel, String>(
  selector: (context, myModel) => myModel.someValue,
  builder: (context, someValue, child) {
    return Text(someValue);
  },
);

Consumerの活用

Consumerを使うことでChangeNotifierに依存するUIのみリビルドすルるとができます。リビルドする必要のない部分を分離することで、パフォーマンスを向上することができます。

Consumer<MyModel>(
  builder: (context, myModel, child) {
    return Column(
      children: [
        child!, // 再描画されない部分
        Text(myModel.someValue), // 再描画される部分
      ],
    );
  },
  child: Text('Static widget'),
);

Riverpodの仕組みと使い方について解説Prev

Related post

  1. Flutterアプリ開発

    Riverpodの仕組みと使い方について解説

    Flutterで利用できる状態管理ライブラリの1つです。Flutter…

  2. Flutterアプリ開発

    Flutterで一覧表示の実装に使える3つの方法

    みなさんは様々なスマホアプリを日頃から触っていると思います。様々なアプ…

  3. Flutterアプリ開発

    Flutterを使ったタスク管理アプリUIの作り方を解説

    Flutterを使ったアプリ開発について勉強してきたら、それらの知識を…

  4. Flutterアプリ開発

    Flutterで簡単なカウンターアプリを作ってみよう

    FlutterではさまざまなUIを実装するためめに、多くのパーツが用意…

  5. ウェブサイト
  6. dart

    Flutterアプリ開発

    FlutterのWebViewとはどんな機能?特徴や実装方法を一挙紹介!

    Webページを表示するモバイルアプリはよくありますよね。Flutter…

PAGE TOP