MVI(Model-View-Intent)アーキテクチャパターンは、リアクティブプログラミングの考え方を取り入れたパターンです。主に以下の3つの要素から構成されています。
Model
- アプリケーションの状態(データ)を表現する部分
- データベースやAPIからデータを取得・保存する責務を持ちます
- ビジネスロジックは含まれません
View
- ユーザーインターフェイスを表す部分
- Modelの状態を反映したUIを構築します
- ユーザーの操作を検知し、Intentを生成して渡します
Intent
- ユーザーの操作や意図を表すオブジェクト
- Viewから生成されたIntentをModelに渡し、Modelの状態を更新する役割があります
簡単な具体例として、ToDo管理アプリでMVIパターンを適用した場合を考えてみましょう。
Model
- ToDoItem: ToDo項目の詳細(タイトル、期限、説明など)を保持するクラス
- ToDoListModel: ToDoItemリストを保持する状態を管理するクラス
View
- ToDoListView: ToDo一覧を表示するUI
- ToDoDetailView: 選択したToDoの詳細を表示するUI
Intent
- AddToDoIntent: 新規ToDoを追加する意図を表すクラス
- DeleteToDoIntent: ToDoを削除する意図を表すクラス
- UpdateToDoIntent: ToDoを更新する意図を表すクラス
ユーザーがToDoListViewで新規ToDoを作成するボタンをタップすると、ToDoListViewはAddToDoIntentを生成します。このIntentはToDoListModelに渡され、ToDoListModelはToDoItemを新規作成し、状態を更新します。更新後、ToDoListModelの状態の変化を検知したToDoListViewがUIを再描画します。
同様に、ToDo削除時はDeleteToDoIntent、ToDo更新時はUpdateToDoIntentが発行され、ModelがIntentに基づいて状態を更新し、Viewに反映されます。
MVI では従来のMVVMやMVPとは異なり、View->Model->Viewの一方向の単一フローになっています。複雑な双方向のデータバインディングを避けることができ、ロジックをシンプルに保つことができます。また、Intentという層を導入することで、ユーザー操作とモデル更新のロジックを分離できるメリットがあります。
ただし、大規模アプリの場合、Intentクラスが肥大化する可能性があり、さらにIntentHandlerのような仲介クラスを作る必要が出てくるなど、複雑さが増すデメリットもあります。