こんにちは。新人プログラマーの岩本です。
今回はFlutterでMVVMを実現するための方法を紹介します。
MVVMは初学者でも扱いやすいアーキテクチャなので、ぜひ最後までご覧ください。
MVVMとは
MVVMとはGUIアーキテクチャの1種です。
GUIアーキテクチャとは、UIとロジックを分離させるもので、MVCやMVPなどがあります。
MVVMは3つの構成要素によって成り立っています。

| 名前 | 役割 | 
|---|---|
| View | UI担当 | 
| ViewModel | ViewとModelの中継役。 Modelの値の変更をViewに通知する役割を持つ。 | 
| Model | データモデルやAPI通信など。 ViewとViewModel以外の全てを担当する。 | 
それぞれの頭文字を取ることで、M(Model)V(View)VM(ViewModel)となります。
ではここからFlutterでMVVMを実現するための方法を紹介します。
またここで紹介する方法はあくまで一例で、絶対のものではありません。
ChangeNotifier
ChangeNotifierとは、Flutter SDKに含まれているクラスです。
notifyListeners() を呼ぶことで、値の変更をViewに通知することができます。
またView側はChangeNotifierProviderでViewModelをcreateできます。
言葉で説明しても伝わらないと思うので、実際の実装例を紹介します。
実装例
事前準備
まずは必要なパッケージをインストールします。
今回はProviderのみでOKです。
flutter pub add providerMVVMを実装
次にview_model.dartを作成し、以下のコードを入力します。
class ViewModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;
  void increment() {
    _count += 1;
    notifyListeners();
  }
}ViewModelはChangeNotifierを継承し、値の変更時にnotifyListeners()を呼び出しています。
次にmain.dart内のMyHomePageクラスを以下のように書き換えます。
class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => ViewModel(),
      builder: (context, _) {
        final viewModel = context.watch<ViewModel>();
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
            title: const Text('ChangeNotifier'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  '${viewModel.count}',
                  style: Theme.of(context).textTheme.headlineMedium,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: viewModel.increment,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ),
        );
      },
    );
  }
}ChangeNotifierProviderでViewModelをcreateし、表示する値はViewModelのものを参照するようにしています。
StateNotifier
StateNotifierとは、Providerパッケージの作者の方が作った状態管理のためのパッケージです。
ChangeNotifierと違い、notifyListeners() を呼ばなくても変更を検知できます。
実装例
事前準備
まず必要なパッケージをインストールします。
今回はRiverpodを使用します。
flutter pub add flutter_riverpodMVVMの実装
次にhome_page_notifier.dartを作成し、以下のコードを入力してください。
// 状態を操作するclass
class HomePageNotifier extends StateNotifier<int> {
  HomePageNotifier(): super(0); // 0で初期化する
  void increment() {
    state += 1;
  }
}
// UIから状態にアクセスできるようにするProvier
// UIはこのProviderを通じて状態にアクセスする
final homePageProvider = StateNotifierProvider((ref) => HomePageNotifier());StateNotifierを使用するには、以下の2つの要素が必要になります。
- 状態を操作するclass(StateNotifierを継承)
- UIから状態にアクセスできるようにするProvider(StateNotifierProvider)
次にmain.dart内のMyHomePageクラスを以下のように書き換えます。
class MyHomePage extends ConsumerWidget {
  const MyHomePage({super.key});
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final homePageState = ref.watch(homePageProvider);
    final homePageNotifier = ref.read(homePageProvider.notifier);
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('StateNotifier'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '$homePageState',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: homePageNotifier.increment,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}homePageProviderをwatchすることで、値の変更を検知してUIが再レンダリングされるようになります。
Notifier
Notifierとは、変更される可能性のある状態を管理するためのProviderです。
使い方はStateNotifierとほぼ同じです。
しかしNotifierの場合は、Riverpod Generatorでコードを自動生成することができます。
実装例
まずは必要なパッケージをインストールします。
flutter pub add flutter_riverpod riverpod_annotationflutter pub add --dev riverpod_generator build_runnerインストールしたパッケージは以下の通りです。
| パッケージ名 | 役割 | 
|---|---|
| flutter_riverpod | FlutterでRiverpodを使用するためのパッケージ | 
| riverpod_annotation | コード生成のためのアノテーションを提供 | 
| riverpod_generator | Riverpodのコード生成を行うためのパッケージ | 
| build_runner | ソースコード生成ツール | 
MVVMの実装
次にhome_page_notifier.dartを作成し、以下のコードを入力してください。
part 'home_page_notifier.g.dart';
@riverpod
class HomePageNotifier extends _$HomePageNotifier {
  @override
  int build() => 0;
  void increment() {
    state += 1;
  }
}次に以下のコマンドを入力して、コードを自動生成してください。
flutter packages pub run build_runner buildするとhome_page_notifier.g.dartが生成され、homePageNotifierProviderが追加されていると思います。
次にmain.dart内のMyHomePageクラスを以下のように書き換えます。
class MyHomePage extends ConsumerWidget {
  const MyHomePage({super.key});
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final homePageState = ref.watch(homePageNotifierProvider);
    final homePageNotifier = ref.read(homePageNotifierProvider.notifier);
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Notifier'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '$homePageState',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: homePageNotifier.increment,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}基本的な書き方はStateNotifierと同じで、homePageNotifierProviderをwatchすることで、値の変更を検知することができます。
まとめ
今回はFlutterでのMVVMの実装例を紹介しました。
個人的には、特別な理由がなければNotifierを使うのが良いと思いました。
MVVMは色々な場面で使えるので、ぜひご自身の手で色々と試してみてください。
ここまでのご閲覧ありがとうございました!
参考にした記事






 
  
  
  
  

コメント