公開日:2020/04/22更新日:2020/08/03
【Kotlin MVP】MVPアーキテクチャで、TODOアプリを作成する #4

アプリ開発におけるアーキテクチャ(設計)の1つに、MVPというものがあります。
本記事は、ToDoアプリの作成を通して、MVPについて学習するシリーズの第4弾です。
第4弾の今回は、Presenterを実装します。
なお、本シリーズで実装するTODOアプリのソースコードは、todo-sample | GitHubにて公開しております。
目次
Presenterの実装
interfaceの実装
Presenterを実装するにあたり、必要な処理を明確にするため、interfaceを作成します。
- TaskContract.kt
interface TaskContract {
interface View {
fun onLoadTasks(tasks: List<Task>)
}
interface Presenter {
fun loadTasks()
fun insertTask(description: String)
fun updateTaskState(task: Task)
fun updateTaskDescription(task: Task, description: String)
fun deleteTask(task: Task)
}
}
TaskContractというinterfaceを作成し、さらにその中に、ViewとPresenterというinterfaceを作成しました。
Viewは、Presenterを利用する側のクラスでimplementされることを想定したinterfaceです。
onLoadTasks()は、Presenterでタスクの一覧取得が行われた後に呼ばれることを想定しており、Viewをimplementしたクラスでは、onLoadTasks()をOverrideし、リスト表示の更新処理を行うようにします。
Presenterは、後に作成するTaskPresenterというクラスでimplementされることを想定したinterfaceです。
loadTasks()は、タスクの一覧取得処理が実装されることを想定しております。
insertTask()は、タスクの追加処理が実装されることを想定しております。
updateTaskState()は、タスクの状態の更新処理が実装されることを想定しております。
updateTaskDescription()は、タスクの内容の更新処理が実装されることを想定しております。
deleteTask()は、タスクの削除処理が実装されることを想定しております。
interfaceは無くても実装できますが、interfaceを実装することで、各クラスに必要な機能を整理することができ、implementしたクラスで、interfaceのメソッドの実装を強制させることができます。
Presenterの実装
続いて、TaskPresenterというMVPのPresenterに該当するクラスを作成します。
- TaskPresenter.kt
class TaskPresenter(private val taskDao: TaskDao, private val view: TaskContract.View): TaskContract.Presenter {
override fun loadTasks() {
val tasks = taskDao.getAll()
view.onLoadTasks(tasks)
}
override fun insertTask(description: String) {
taskDao.insert(Task(0, 0, description))
loadTasks()
}
override fun updateTaskState(task: Task) {
task.state++
if (task.state > 2) task.state = 0
taskDao.update(task)
loadTasks()
}
override fun updateTaskDescription(task: Task, description: String) {
task.description = description
taskDao.update(task)
loadTasks()
}
override fun deleteTask(task: Task) {
taskDao.delete(task)
loadTasks()
}
}
TaskPresenterは、先ほど実装した、TaskContractのPresenterをimplementしております。ですので、Presenterに実装されているメソッドを、Overrideしております。
コンストラクタで、前回の記事で実装したTaskDaoと、TaskContractのViewをimplementしたクラスを受け取るよう実装されております。
各メソッドでは、TaskDaoから、データベースへアクセスする処理が実装されております。
また、追加、更新、削除の処理が実行された後は、loadTasks()を呼びだし、タスクの一覧取得を行うよう実装しております。loadTasks()では、タスクの一覧を取得した後、結果をTaskContract.ViewのonLoadTasks()に渡すよう実装されております。
なお、現段階では、TaskDao経由でデータベースへのアクセスを行なっておりますが、将来的には、Repository経由でアクセスするよう変更する予定です。
Presenterを呼びだす処理の実装
最後に、MainFragmentに実装されているデータベースへのアクセス処理を削除し、Presenter経由でデータベースにアクセスするよう修正します。
- MainFragment.kt
class MainFragment : Fragment(), TaskContract.View {
override fun onLoadTasks(tasks: List<Task>) {
adapter.tasks = tasks
}
private lateinit var adapter: TasksAdapter
private lateinit var presenter: TaskPresenter
(省略)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
(省略)
val db = TaskDatabase.getInstance(context)
presenter = TaskPresenter(db.taskDao(), this)
presenter.loadTasks()
addTaskButton.setOnClickListener {
presenter.insertTask("New Task")
}
}
val itemListener = object : TaskItemListener {
override fun onStateClick(task: Task) {
presenter.updateTaskState(task)
}
override fun onDescriptionClick(task: Task) {
presenter.updateTaskDescription(task, "Updated Task")
}
override fun onDeleteClick(task: Task) {
presenter.deleteTask(task)
}
}
(省略)
}
MainFragmentは、TaskContractのViewをimplementし、onLoadTasks()をOverrideしております。onLoadTasks()には、タスクの一覧取得の結果が渡ってくるので、リストの更新処理を実装しておきます。
onViewCreated()では、TaskPreseterの生成と、タスクの一覧取得を行うloadTasks()の呼び出しを行なっております。
追加ボタンタップ時に呼ばれるaddTaskButton.setOnClickListenerでは、TaskPreseterのinsertTask()を呼び出し、タスクの追加処理を行うよう実装しました。
タスクの状態表示部分タップ時に呼ばれるonStateClick()では、TaskPreseterのupdateTaskState()を呼び出し、タスクの状態更新処理を行うよう実装しました。
タスクの内容表示部分タップ時に呼ばれるonDescriptionClick()では、TaskPreseterのupdateTaskDescription()を呼び出し、タスクの内容更新処理を行うよう実装しました。
タスクの削除ボタンタップ時に呼ばれるonDeleteClick()では、TaskPreseterのdeleteTask()を呼び出し、タスクの削除処理を行うよう実装しました。
実行結果
この章の修正内容はPresenterの実装 | GitHubからも確認頂けます。本記事には、重要箇所のコードのみを抜粋して掲載しておりますので、その他の修正内容に関しましては、こちらからご確認いただけると幸いです。
今回の実装はここまでとなります。
次回は、Repositoryの実装していく予定です。
ありがとうございました。