什么是MVP?
MVP的全称为Model-View-Presenter,Model提供数据,View负责显示,Controller/Presenter负责逻辑的处理。
来自维基百科的模型描述
Model-View-Presenter (MVP) 是用户界面设计模式的一种,被广泛用于便捷自动化单元测试和在呈现逻辑中改良分离关注点(separation of concerns)。
- Model 定义用户界面所需要被显示的资料模型,一个模型包含着相关的业务逻辑。
- View 视图为呈现用户界面的终端,用以表现来自 Model 的资料,和用户命令路由再经过 Presenter 对事件处理后的资料。
- Presenter 包含着组件的事件处理,负责检索 Model 获取资料,和将获取的资料经过格式转换与 View 进行沟通。
Android 实现
代码参考谷歌官方的Demo。To-DoApp的todo-mvp-kotlin分支
1. 定义BaseView
和BasePresenter
- 其中
BaseView
持有一个presenter
成员。实现BasePresenter
要实现start()
方法。
1
2
3
interface BaseView<T> {
var presenter: T
}
1
2
3
interface BasePresenter {
fun start()
}
2.明确功能需求,编写功能级的View和Presenter
以Task详情页为例,用户能执行4种操作,分别是编辑Task、删除Task、改变Task完成状态(已完成、未完成)。根据上面的需求,我们Task详情页的Presenter代码如下。
1
2
3
4
5
6
7
8
9
10
interface Presenter : BasePresenter {
// 编辑Task
fun editTask()
// 删除Task
fun deleteTask()
// 完成Task
fun completeTask()
// 激活Task
fun activateTask()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
interface View : BaseView<Presenter> {
val isActive: Boolean
// 是否显示加载中
fun setLoadingIndicator(active: Boolean)
// 显示找不到Task
fun showMissingTask()
// Task为空时,隐藏标题
fun hideTitle()
// 显示并显示标题
fun showTitle(title: String)
// Task为空时,隐藏描述
fun hideDescription()
// 显示并显示描述
fun showDescription(description: String)
// 显示Task的完成状态
fun showCompletionStatus(complete: Boolean)
// 跳转编辑Task的Activity
fun showEditTask(taskId: String)
// 执行Task删除后的逻辑
fun showTaskDeleted()
// 显示Task已完成的界面
fun showTaskMarkedComplete()
// 显示Task已已激活的界面
fun showTaskMarkedActive()
}
3.业务代码分析
TaskDetailActivity
是容器,具体实现逻辑在TaskDetailFragment
。
- 在
TaskDetailActivity
里,将TaskDetailPresenter
和TaskDetailFragment
(已实现View
接口) 绑定在一起,如何绑定见下文2。1 2 3 4 5 6 7
override fun onCreate(savedInstanceState: Bundle?) { ... //取得TaskDetailFragment实例 val taskDetailFragment = ... TaskDetailPresenter(..., taskDetailFragment) ... }
TaskDetailPresenter
接收实现了View
接口的UI,即TaskDetailFragment
,并实现Presenter
接口,在构造方法的时候通过调用taskDetailView.presenter = this
绑定在一起。1 2 3 4 5 6 7 8 9 10 11 12 13
class TaskDetailPresenter( ... private val taskDetailView: TaskDetailContract.View ) : TaskDetailContract.Presenter { init { taskDetailView.presenter = this } ... //实现TaskDetailContract.Presenter的方法 ... }
TaskDetailFragment
实现View
接口,并持有presenter
实例和Presenter进行交互。在onResume
的时候,调用Presenter的start()
方法启动Presenter,开始交互。1 2 3 4 5 6 7 8 9 10 11 12 13
class TaskDetailFragment : Fragment(), TaskDetailContract.View { override lateinit var presenter: TaskDetailContract.Presenter override fun onResume() { super.onResume() presenter.start() } ... //实现TaskDetailContract.View的方法和属性 ... }
TaskDetailFragment
调用TaskDetailPresenter
的方法执行业务逻辑,TaskDetailPresenter
调用TaskDetailContract.View
的方法,让TaskDetailFragment
更新页面UI。- 调用
presenter.deleteTask()
删除Task1 2 3 4 5
override fun onOptionsItemSelected(item: MenuItem): Boolean { val deletePressed = item.itemId == R.id.menu_delete if (deletePressed) presenter.deleteTask() return deletePressed }
- presenter根据实际情况调用
View
的方法更新UI。如果taskId为空,则调用showMissingTask()
显示没有Task,否则执行删除逻辑并调用showTaskDeleted()
显示删除成功。1 2 3 4 5 6 7 8
override fun deleteTask() { if (taskId.isEmpty()) { taskDetailView.showMissingTask() return } tasksRepository.deleteTask(taskId) taskDetailView.showTaskDeleted() }
TaskDetailFragment
执行最终显示UI的方法。1 2 3 4 5 6 7 8
override fun showMissingTask() { detailTitle.text = "" detailDescription.text = getString(R.string.no_data) } override fun showTaskDeleted() { activity?.finish() }
- 调用