はじめに
- AndroidのMVPアーキテクチャに関する調査を行った
- アーキテクチャを学ぶときはandroid-architectureを見ろとよく言われている。しかし、それは時間がかかるし、アーキテクチャ自体は抽象的な概念の話なので、それでは齟齬が発生する可能性がある。プロダクトに関わる上で概念という高度なレイヤから落として具体例を提示すると、学習時間の短縮やレビューのしやすさなど、メリットがいくつかある
- ここでは、android-architectureのkotlin-mvpで何をやっているかを具体的に言語化
- 上記の例の場合の話なので、必ずしもこの具体例がどのような場合にも当てはまるわけではない。これを指針に柔軟に実装を行なっていきたい
具体例
パッケージ構成
todoapp以下が以下の通り
todoapp
│ BasePresenter.kt
│ BaseView.kt
│
├─addedittask
│ AddEditTaskActivity.kt
│ AddEditTaskContract.kt
│ AddEditTaskFragment.kt
│ AddEditTaskPresenter.kt
│
├─data
│ │ Task.kt
│ │
│ └─source
│ │ TasksDataSource.kt
│ │ TasksRepository.kt
│ │
│ ├─local
│ │ TasksDao.kt
│ │ TasksLocalDataSource.kt
│ │ ToDoDatabase.kt
│ │
│ └─remote
│ TasksRemoteDataSource.kt
│
├─statistics
│ StatisticsActivity.kt
│ StatisticsContract.kt
│ StatisticsFragment.kt
│ StatisticsPresenter.kt
│
├─taskdetail
│ TaskDetailActivity.kt
│ TaskDetailContract.kt
│ TaskDetailFragment.kt
│ TaskDetailPresenter.kt
│
├─tasks
│ ScrollChildSwipeRefreshLayout.kt
│ TasksActivity.kt
│ TasksContract.kt
│ TasksFilterType.kt
│ TasksFragment.kt
│ TasksPresenter.kt
│
└─util
AppCompatActivityExt.kt
AppExecutors.kt
DiskIOThreadExecutor.kt
EspressoIdlingResource.kt
SimpleCountingIdlingResource.kt
ViewExt.kt
- todoapp直下には全てのpresenterが継承すべきBasePresenterと全てのViewが継承すべきBaseViewが存在する。
- util,data以外は画面単位で整理されており、例えばtasks以下にはtasks画面で使用する
- Activity,Fragment,Presenter,CustomeLayout,enumが定義されたTasksFilterType,その画面で使用するViewとPresenterのInterfaceが定義されたContractが存在する。ViewとPresenterで画面単位でまとめる。
- dataはModel層で使用するクラスがまとめられている。
各層で行うべきこと
便宜的に、Hogeという画面を作る場合で考えていきます
View
- BaseViewインターフェースを定義
interface BaseView<T> {
var presenter: T
}
- HogeContractインターフェースにBaseViewを継承したViewインターフェースを定義
- Viewのインターフェースを定義していく。Presenterは直接Viewを触らずにここで定義されたメソッドを介してViewに依頼をする
- HogeContract.Viewを継承したHogeFragmentを実装する
- プロパティにHogeContract.Presenter型のPresenterをlateinitで定義しておく
- 各種イベント発生時にPresenterに移譲していくように処理を書いていく
- 各種UIのセットアップ,トースト表示やonClickなど画面入出力,intentの作成,他Activityの起動など、Viewに関する処理はここで行う
- HogeActivityを実装する
- HogeFragmentの生成やPresenterの生成を行う。その際にInjectionを使ってデバッグ時にModel層の部分をmockに差し替えられるように作られている
- 各種UIのセットアップ,トースト表示やonClickなど画面入出力,Intentの作成,他Activityの起動など、Viewに関する処理はここで行う
Presenter
- BasePresenterインターフェースを定義
interface BasePresenter {
fun start()
}
- HogeContractインターフェースにBasePresenterを継承したPresenterインターフェースを定義
- Presenterのインターフェースを定義していく。Viewはここで定義されたメソッドを介してPresenterに移譲をする
- メソッドの名前はViewのonClickでPresenterに移譲されるから
onClick
という名前にするのではなく、addNewTask
のようにきちんと動作を表す命名を行う
- HogeContract.Presenterを継承したHogePresenterを実装する
- プライマリコンストラクタでRepositoryとViewをプロパティにセットする。それぞれ型はインターフェースの物にしておく(この例ではHogeContract.Viewを使うなど)
- HogeContract.Viewに定義されたインターフェースを介してViewに入出力を依頼する
- 他Activityの起動やIntent作成、外部との通信などAndroid依存の機能はここでは極力使わない。そういったものはViewやModelで行う
Model
- Repositoryパターンで実装する
- データ永続化にRoomを使用している
- 非同期処理にHandler()を使用している
- ネットワークの通信による遅延した動作をシミュレートしているだけの模様