こんにちは。新人プログラマーの岩本です。
今回は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 provider
MVVMを実装
次に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_riverpod
MVVMの実装
次に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_annotation
flutter 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は色々な場面で使えるので、ぜひご自身の手で色々と試してみてください。
ここまでのご閲覧ありがとうございました!
コメント