システム開発部のTです。私自身、趣味でアプリを開発しながらスキルアップしようとしておりますが、Flutterにおいては自分がこれだ!と思うアーキテクチャーが固まっていない状態です。 そういった中、試行錯誤しているうちに、ようやくスッキリとした形でコーディングできたので紹介します。 個人的にAndroidアプリの開発のなかでDataBindingを用いてのMVVM(Model-View-ViewModel)が主流ですが、基本的にそれと同等の動きを、Flutterでも目指してみました。 開発準備 それでは、以下のコマンドを実行し、プロジェクトを生成してください。(以下、helloworldにしていますが、任意のプロジェクト名にしてください。) (※Flutterの開発環境は構築済みの前提で進めていきます。) Riverpodの追加 本件では、グローバルに利用可能なProviderライブラリとしてRiverpodを利用いたします。pubspec.yamlのdependensiesに以下の内容を追記してください。 その後、Pub getで反映してください。 main.dartの整理 プロジェクト作成直後に生成されているmain.dartを見てみましょう。(以下、不要なコメントは削除済みです) このままだと見栄えが悪いので、classごとにファイルを分けます。分けたあとの内容が以下になります。 動作確認 上記までコード分けしたら、動作確認してみます。以下の画面が表示されることを確認してください。 これで開発準備は完了です。 概要 本件においては、デフォルトで作成されるカウンターアップの処理をそのままMVVMに置き換えていきます。DBやAPIのアクセスは行わないので物足りないかもしれませんが、基本の実装を見てもらうことで、ご理解いただきたいです。 また、本件でのMVVM(+Repositoryパターン)のイメージは以下になります。 ProviderScopeの実装 本件においては、RiverpodのProviderScope配下で動くことを前提としているため、main.dartにて以下の実装をお願いします。 Modelの実装 MVVMのModelに相当するクラスを実装します。本件ではResultModelで定義し、インクリメントしたカウンターの内容を保持するクラスになります。 ResultModel自体はint属性のcounterを持っているだけです。また、本件ではDIを意識した実装をしたかったので、ProviderにResultModelのインスタンスを保持するようにしています。要するにProvider=DIコンテナの役割を持たせました。 Repositoryの実装 Modelへのアクセスを隠蔽することを意識し、Repositoryパターンでの実装になります。こちらもDIを意識して実装します。 Unitテストを意識して、MyHomeRepositoryの抽象クラスを用意し、実際の処理はMyHomeRepositoryImplクラスに委ねます。コンストラクタの引数にResultModelの受け口を用意し、本クラスをDIコンテナ(Provider)に保持するときに、ref.readでModelの実装時にDIコンテナに保持しているResultModelのインスタンスを引数に渡しています。 本クラスでやっていることは単純にmodelのcounterをインクリメントし、model自体を呼び出し元に返すだけのものです。本アプリではAPIおよびDBにアクセスすることがないので、上記のように実装しています。 ViewModelの実装 MVVMのViewModelの実装になります。本件のViewModelはChangeNotifierクラスを継承して実装します。 呼び出し元のWidgetはgetCounter()からインクリメントされる値を取得し、画面に表示します。画面右下の「+」ボタンをタップすると、incrementCounter()を実行し、インクリメントされたカウンターを保持しているResultModelを受け取り、ResultModelのcounter値を本クラスの_counterに設定されます。その後、notifyListeners()を実行すると、呼び出し元のWidgetがリビルドされるため、再度getCounter()がコールされ、更新後の_counter値を画面に表示することになります。 MyHomePageの実装 MVVMのViewに該当する処理の実装になります。実装内容については、実際のコードを見てもらうほうが早いので、以下のコードを参照後に説明します。 既存のMyHomePageの親クラスStatefulWidgetをConsumerWidgetに変更します。 上記に変更すると、build()メソッドの実装が強要されます。buildメソッドのWidgetRefを利用し、ref.watch()メソッドの引数にViewModelのProvider「myHomeViewModelProvider」を指定することで、Providerに保持しているMyHomeViewModelを取得できます。あとは、returnに_MyHomePageStateクラスのbuild()のreturnの内容を移植し、_counterはviewModel.getCounter()に、_incrementCounterはviewModel.incrementCounterに、それぞれ置き換えて実装完了です。 今までの_MyHomePageStateは不要なので削除します。 動作確認 ここまで実装完了したら、アプリを起動してください。変更前と同様に動作することができればOKです。変更が大きかったわりに今までと動作が変わらないので達成感無いかもしれませんが、API、およびDB等も含めて、アクセス時は同様の実装になるかと思います。 まとめ アーキテクチャーの検討ということで、本件ではAndroidっぽい感じのMVVMで実装しましたがいかがだったでしょうか。MVVM以外にも検討するべきアーキテクチャーは存在しますので、今後も記事にあげていこうと思っております。 なお、開発者T的には本件のMVVMがシンプルでいいかな?と思っています。 以上、ありがとうございました。

Read more of this post