
MVC
简介
将应用组件分为三部分:模型-视图-控制器
- 模型(model) 用于封装业务逻辑相关的数据。model层有对数据直接访问的权力,例如数据库访问。model层 不依赖 view层和controller层,也就是说model层,不关心它会被如何显示或是如何操作。但是model层中数据变化一般会通过一种刷新机制被公布。为了实现这种机制,哪些监视model数据的controller层需要事先在此注册,从而观察数据改变
- 视图(view) 与用户交互,实现数据有目的的显示。view层没有处理逻辑。
- 控制器(controller) 起到不同层面的组织作用,控制应用程序流程。它处理事件,并做出响应。事件包括:用户操作,数据改变。

那在Android里是什么充当View,什么充当Model,什么充当Controller呢?
View:Acitivity(View)、Fragment(View)视图,在android里xml布局转成View后,加载到了Activity/Fragment里了。
Controller:Controller对应着Activity/Fragment,绑定UI,处理各种业务。
Model:数据的获取,存储,更新
优点
view与model隔离,view换了,model不影响。model换其他的数据源,view层也不受影响。一个view可以连接多个model,有些model可以复用。比如说你这个页面需要用户信息,另外一个界面也需要用户信息。
缺点
这里我们主要指Android上的缺点,不适合在Android开发上使用。在Android开发中,View的相关内容和Controller都写到一起了,==会让Activity/Fragment越来越臃肿==。
MVP
简介
于是大家都觉得MVC套在Android上不好。VC的代码会越来越多,如果要处理复杂的逻辑,Activity的代码上千上行。于是大家开始剥离VC里的代码。
这个用起来爽了很多,Activity的代码量也没这么多了。
大量的逻辑代码抽取到了Presenter层。
-
View:Activity、Fragment
-
Presneter:逻辑层
-
Model:数据处理
怎么调用逻辑层的方法呢?
View层持有Presenter层的引用或者通过管理类管理Presenter,总之View可以直接拿到Presenter,这样子,View就可以调用Presenter里的方法了。比如说Presenter你给我获取一个这个页面的分类
Presenter层如何更新UI呢
当View层去获取/创建Presenter的时候,把接口给到Presenter,比如说Presenter层获取到分类以后,通过接口更新UI即可。

优点
剥离了View和Controller,解决了复杂的业务Activity过于庞大的问题
缺点
- 更新UI需要主意线程,UI控件是否已经销毁
假如我们去请求一个数据,这个时候请求是耗时的,数据回来了,可是界面已经被用户关掉了,数据回来以后,我们得判断UI控件是否还存在。
- 如果多个地方使用到同一个Presenter,可能会存在一些用不上的接口.
demo
View层
/**
* V层 负责交互、显示
*/
class RegisterActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var phoneET: EditText
private lateinit var pwdET: EditText
private lateinit var registerBtn: Button
//持有presenter层
private lateinit var mPresenter: RegisterPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_register)
mPresenter = RegisterPresenter(this)
phoneET = findViewById(R.id.phoneET)
pwdET = findViewById(R.id.pwdET)
registerBtn = findViewById(R.id.registerBtn)
registerBtn.setOnClickListener(this)
}
override fun onClick(v: View) {
if (v.id == R.id.registerBtn) {
//通过中间层 请求数据
mPresenter.regist(
phoneET.text.toString(),
pwdET.text.toString()
)
}
}
fun showMessage(message:String){
Toast.makeText(this, "$message", Toast.LENGTH_SHORT).show()
}
}
presenter 层
/**
* 中间层-
* 1、抽离Ativity中的逻辑代码
* 2、请求数据
*/
class RegisterPresenter {
//持有model层
private lateinit var mRegisterModel: RegisterModel
private lateinit var mActivity: RegisterActivity
//持有View层 一般用接口
constructor(activity: RegisterActivity){
mActivity = activity
mRegisterModel = RegisterModel()
}
fun regist(phone:String,pwd:String) {
MainScope().launch {
mRegisterModel.regist(phone,pwd){
//更新UI
if(it){
mActivity.showMessage("登录成功")
}else{
mActivity.showMessage("登录失败")
}
}
}
}
}
Model层
/**
* 数据层 - 请求数据
* 1.数据库
* 2.网络
* 3.其他app
*/
class RegisterModel {
//不需要持有view、presenter层 通过回调将数据传给presenter层
suspend fun regist(phone: String, pwd: String,response:(Boolean)->Unit) {
delay(2000)
response.invoke(Random.nextBoolean())
}
}
网友评论