公開日:2020/04/15更新日:2020/08/03
【Kotlin MVP】todo-mvp-kotlinでMPVを学ぶ #3 | MVPの処理の流れについて

- MVPって何?
- MVPの実装方法を1から学びたい
アプリ開発におけるアーキテクチャ(設計)の1つに、MVPというものがあります。
本記事は、Googleが公開している、todo-mvp-kotlinというサンプルアプリを通して、MVPについて学ぶシリーズの第3弾です。
今回は、MVPの処理の流れについて解説していきます。
目次
シーケンス図
前回の記事で、todo-mvp-kotlinアプリが、タスク一覧画面、タスク追加・編集画面、タスク詳細画面、統計画面で構成されていると解説致しました。
今回MVPの処理の流れを解説するにあたり、タスク一覧画面に焦点を当て解説していきますが、基本的な処理の流れは、他の画面も同じです。
ではまず、タスク一覧画面にて、アプリ起動から、タスクの一覧表示までのシーケンスを紹介致します。
TasksActivityのonCreateでは、ViewのTasksFragmentの生成、ModelのTasksRepositoryの生成、PresenterのTasksPresenterの生成を行なっております。
onResumeが呼ばれると、
TasksActivity → TasksFragment → TasksPresenter → TasksRepository → データベース
TasksActivity ← TasksFragment ← TasksPresenter ← TasksRepository ← データベース
という流れで、データの取得を行います。
詳しい処理については、次項で解説いたします。
MVPの処理の流れについて
では、シーケンス図で紹介した処理のコードを詳しく見ていきます。
なお、今回はMVPの処理の流れに焦点をあてているため、それ以外の部分は”(省略)”と記載しております。
TasksActivity.onCreate()
override fun onCreate(savedInstanceState: Bundle?) {
(省略)
// TasksFragmentの生成
val tasksFragment = supportFragmentManager.findFragmentById(R.id.contentFrame)
as TasksFragment? ?: TasksFragment.newInstance().also {
replaceFragmentInActivity(it, R.id.contentFrame)
}
// TasksRepository、TasksPresenterの生成
tasksPresenter = TasksPresenter(Injection.provideTasksRepository(applicationContext),
tasksFragment).apply {
(省略)
}
}
TasksActivityのonCreateでは、TasksFragment、TasksRepository、TasksPresenterのインスタンスの生成を行なっております。
TasksRepositoryは、TasksPresenter生成時の引数の、Injection.provideTasksRepository()部分で生成処理が行われております。
TasksFragment.newInstance()
fun newInstance() = TasksFragment()
TasksFragmentのnewInstance()では、TasksFragmentのインスタンスの生成を行なっております。
TasksRepository.getInstance()
@JvmStatic fun getInstance(tasksRemoteDataSource: TasksDataSource,
tasksLocalDataSource: TasksDataSource): TasksRepository {
return INSTANCE ?: TasksRepository(tasksRemoteDataSource, tasksLocalDataSource)
.apply { INSTANCE = this }
}
TasksRepositoryのgetInstance()では、TasksRepositoryのインスタンスがまだ生成されていない場合、新たにインスタンスの生成を行なっております。
getInstance()は、InjectionのprovideTasksRepository()から呼ばれます。
TasksPresenter.TasksPresenter()
class TasksPresenter(val tasksRepository: TasksRepository, val tasksView: TasksContract.View)
: TasksContract.Presenter {
(省略)
init {
tasksView.presenter = this
}
(省略)
}
TasksPresenterのコンストラクタでは、TasksRepositoryとTasksFragment(引数のtasksView)を受け取っております。
また、initにて、TasksFragmentのpresenterに、自身を指定しております。こうすることで、TasksFragmentから、TasksPresenterを呼び出せるようになります。
TasksFragment.onResume()
override fun onResume() {
super.onResume()
presenter.start()
}
TasksFragmentのonResume()では、TasksPresenterのstart()を呼び出しております。
TasksPresenter.start()
override fun start() {
loadTasks(false)
}
override fun loadTasks(forceUpdate: Boolean) {
// Simplification for sample: a network reload will be forced on first load.
loadTasks(forceUpdate || firstLoad, true)
firstLoad = false
}
private fun loadTasks(forceUpdate: Boolean, showLoadingUI: Boolean) {
(省略)
tasksRepository.getTasks(object : TasksDataSource.LoadTasksCallback {
(省略)
})
}
TasksPresenterのstart()では、自身のloadTasks()を呼び出しております。
loadTasks()では、TasksRepositoryのgetTasks()を呼び出しております。
TasksRepository.getTasks()
override fun getTasks(callback: TasksDataSource.LoadTasksCallback) {
(省略)
if (cacheIsDirty) {
(省略)
} else {
// Query the local storage if available. If not, query the network.
tasksLocalDataSource.getTasks(object : TasksDataSource.LoadTasksCallback {
override fun onTasksLoaded(tasks: List) {
refreshCache(tasks)
callback.onTasksLoaded(ArrayList(cachedTasks.values))
}
override fun onDataNotAvailable() {
getTasksFromRemoteDataSource(callback)
}
})
}
}
TasksRepositoryのgetTasks()では、TasksLocalDataSourceのgetTasks()を呼び出し、データベースからデータの取得を行なっております。
データの取得が終わると、引数で受け取ったコールバックのonTasksLoaded()を呼び出し、結果を返しております。
TasksPresenter.onTasksLoaded()
override fun onTasksLoaded(tasks: List) {
val tasksToShow = ArrayList()
(省略)
processTasks(tasksToShow)
}
private fun processTasks(tasks: List<Task>) {
if (tasks.isEmpty()) {
// Show a message indicating there are no tasks for that filter type.
processEmptyTasks()
} else {
// Show the list of tasks
tasksView.showTasks(tasks)
// Set the filter label's text.
showFilterLabel()
}
}
TasksPresenterのonTasksLoaded()では、自身のprocessTasks()を呼び出しております。
processTasks()では、TasksFragmentのshowTasks()を呼び出しております。
TasksFragment.showTasks()
override fun showTasks(tasks: List) {
listAdapter.tasks = tasks
tasksView.visibility = View.VISIBLE
noTasksView.visibility = View.GONE
}
TasksFragmentのshowTasks()では、タスクを一覧表示する処理が実装されております。
以上が大まかなMVPの処理の流れとなります。大体の流れはつかめましたでしょうか?
次回からは、todo-mvp-kotlinを参考にしながら、実際にTODOアプリを作成していきたいと考えております。
ありがとうございました。