プログラマになる

組み込みエンジニアで主にC言語、時々C#をやっている人の技術メモです。最近はAndroidも少しずつ勉強中

学習中「Android アプリ設計パターン入門」を読んで学ぶMVVMアーキテクチャ

はじめに

「Android アプリ設計パターン」
「第2章 MVVMパターンを使ったアプリ構成」から学んだことをまとめます。

Androidアプリ設計パターン」では「Android Architecture Blueprints」
TODOアプリを例にMVVMパターンの解説しています。

私はKotlinの勉強も兼ねて「Android Architecture Blueprints」の
「dev-todo-mvvm-live-kotlin」リポジトリを閲覧しました。

そのため本稿に記載するソースコード
「dev-todo-mvvm-live-kotlin」リポジトリのものになります。

peaks.cc

github.com

学んだこと

以下に記載するのがAndroidMVVMパターン
構築するための基本要素です。
これらの各役割をざっくり記載します。

  • Model
  • ViewModel
  • Navigator
  • Activity
  • Fragment

Model

データベースへのアクセスやAPIの呼び出しなど、
アプリケーションのロジックをModelに定義する。

ViewModel

例えば詳細表示に必要なタスクの状態、タイトル・概要の読み込みを行う。
情報の引き出しにはコンストラクト時に渡されるModelを利用する。

Navigator

Navigatorにアクションのインタフェースを定義する。
Navigatorはインタフェースであるため
利用するには実装済みのインスタンスが必要となる。
アクションなので画面遷移などに関連する処理をNavigatorに定義するみたい。

Fragment

Viewを所持し、UIの振る舞いを保証する。
ユーザーがコンポーネントを操作したときの動作を決めたり、
View ↔ ViewModelのデータバインディング設定を行い表示する情報を決める

Activity

全オブジェクトのライフサイクルを管理する。
主ににModel・ViewModel・Navigatorのインスタンスを作成し管理する。

ModelとViewModelの作成

ViewModelの生成方法はViewModelFactory.ktに定義されている。
ここでViewModelごとにどのModelを作成しInjectionするか決めているっぽい。 ActivityからViewModelを作成するときにはAppCompatActivityExt.ktのobtainViewModelを利用して必要なViewModelを生成している。

呼び出し1 TaskDetailActivity.kt
fun obtainViewModel(): TaskDetailViewModel = obtainViewModel(TaskDetailViewModel::class.java)
呼び出し2 AppCompatActivityExt.kt
fun <T : ViewModel> AppCompatActivity.obtainViewModel(viewModelClass: Class<T>) =
        ViewModelProviders.of(this, ViewModelFactory.getInstance(application)).get(viewModelClass)
呼び出し3 ViewModelFactory.kt
fun getInstance(application: Application) =
                INSTANCE ?: synchronized(ViewModelFactory::class.java) {
                    INSTANCE ?: ViewModelFactory(application,
                            Injection.provideTasksRepository(application.applicationContext))
                            .also { INSTANCE = it }
                }

Navigatorの作成

Navigatorの作成というよりはNavigatorの実装になる。
ActivityにNavigatorを実装しViewModelのCommandと紐付ける。

interface TaskDetailNavigator {

    fun onTaskDeleted()

    fun onStartEditTask()
}

class TaskDetailActivity : AppCompatActivity(), TaskDetailNavigator {
    ︙
    override fun onCreate(savedInstanceState: Bundle?) {
        ︙
        taskViewModel = obtainViewModel()
        subscribeToNavigationChanges(taskViewModel)
    }
  
    private fun subscribeToNavigationChanges(viewModel: TaskDetailViewModel) {
        val activity = this@TaskDetailActivity
        viewModel.run {
            editTaskCommand.observe(activity,
                    Observer { activity.onStartEditTask() })
            deleteTaskCommand.observe(activity,
                    Observer { activity.onTaskDeleted() })
        }
    }
  
    override fun onTaskDeleted() {
        ︙
    }

    override fun onStartEditTask() { 
        ︙
    }

まとめ

Android MVVMパターンは各クラスの役割を理解することが大切!!

  • Modelにはデータ取得などのロジックを書く
  • ViewModelはユーザの操作やFragment、Activityの処理の橋渡し
  • Navigatorはアクションのインタフェースを決める
  • ActivityはModel・ViewModel・Navigatorのインスタンスを生成・管理する
  • FragmentはViewを持ち、コンポーネントの表示・振る舞いを決める