mvvm模式和mvc的区别_Android 开发中的架构模式 -- MVC / MVP / MVVM
预备知识
了解 Android 基本开发
看完本文可以达到什么程度
了解如何分析一个架构模式
掌握 MVC,MVP,MVVM 架构定义和实现
更多面试内容,面试专题,flutter视频 全套,音视频从0到高手开发。
关注GitHub:https://github.com/xiangjiana/Android-MS免费获取面试PDF合集免费提供简历修改建议,获取大厂面试PDF和视频教程
文章概览
一、什么是架构
关于架构的定义,其实在很多书籍和文章中都是不同的,很难做一个统一。这里列举两个定义:
在维基百科里是这样定义的:
软件架构是一个系统的草图。软件架构描述的对象是直接构成系统的抽象组件。各个组件之间的连接则明确和相对细致地描述组件之间的通讯。在实现阶段,这些抽象组件被细化为实际的组件,比如具体某个类或者对象。
在 IEEE 软件工程标准词汇中是这样定义的:
架构是以组件、组件之间的关系、组件与环境之间的关系为内容的某一系统的基本组织结构,以及指导上述内容设计与演化的原理。
在看过茫茫多的架构定义以后,我理解的架构是这样的:
1.为了解决特定的问题而提出
2.按照特定的原则将系统整体进行模块/组件/角色的划分
3.建立模块/组件/角色间的沟通机制
具体解释一下,首先是要有特定的问题,没有问题空谈架构,仿佛是空中楼阁,没有实用价值,而对应到不同的问题,会有不同的解决方式。
其次是模块的划分要根据特定的原则,没有原则随意划分,也就无从去评估一个架构的好坏。最后就是模块间的通信机制,让系统成为一个整体.
最后,架构模式,其实更多的是一种思想,一种规则,往往一种架构模式可能会有不同的实现方式,而实现方式之间,只有合适与否,并没有对错之分。
二、如何分析一种架构模式
上面我们介绍了架构的定义,根据这个定义,我们在后面分析架构模式的时候,也会从这三方面进行。
2.1.架构解决了什么问题
知道了架构模式要解决的问题,我们才能针对性的去看,去想其解决方法是否得当,是否合适。
2.2.架构模式是如何划分角色的
架构中最重要的就是角色 / 模块的划分,理解了架构模式中的角色划分,才能更好的理解其结构。
2.3.角色间是如何通信的
角色间的通信也是重要的。相同的角色划分,采用不同的通信方式,往往就构成了不同的架构模式。
角色间通信我们可以理解为数据的流向。在 Android 开发中,通信中的数据可以理解为两种,一种是数据结构,也就是网络请求,本地存储等通信使用的 JavaBean,另一种是事件,也就是控件产生的动作,包括触摸,点击,滑动等等。我们在通信过程中,也主要关注这两种数据。
三、常见的架构模式有哪些
对于我们 Android 开发者来说,常见的架构模式基本上就是 MVC,MVP,MVVM,这三种也是开发 GUI 应用程序常见的模式。
除此之外还有 分层模式,客户端-服务器模式(CS模式),主从模式,管道过滤器模式,事件总线模式 等等。
这篇文章还是具体分析 MVC,MVP,MVVM 这三种架构模式。
四、不使用架构之前 App 是怎么开发的
我们在了解架构的定义以后,可能会想,为什么要用这些架构模式呢?在我们不了解这些模式之前,也是一样的开发。类似设计模式,其实架构模式的目的不是为了让应用软件开发出来,而是让结构更清晰,分工更明确,扩展更方便等等。
我们可以看看,在不使用架构模式之前我们是怎么开发的。
举个简单的栗子,我们界面上有 EditText
,TextView
,Button
三个控件,要实现的功能也比较简单:
1.
EditText
接受用户输入的内容
2.处理用户输入的数据
3.数据处理后输出到TextView
中
4.点击Button
清空用户的输入
界面如下:
我们看看不使用架构模式是怎么开发的,也就是我们一般常用的开发方式:
4.1. 首先在 xml 设计界面
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="10dp"tools:context=".MainActivity"><TextViewandroid:id="@+id/titleText"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Normal" /><EditTextandroid:id="@+id/edit"android:layout_width="match_parent"android:layout_height="50dp"android:textColor="@android:color/darker_gray" /><TextViewandroid:id="@+id/msgText"android:layout_width="wrap_content"android:layout_height="30dp"android:layout_marginTop="10dp"android:text="default msg"android:textColor="@android:color/darker_gray" /><TextViewandroid:id="@+id/clearText"android:layout_width="match_parent"android:layout_height="30dp"android:layout_marginTop="10dp"android:background="@color/colorPrimary"android:gravity="center"android:text="clear"android:textColor="@android:color/white" /></LinearLayout>
1.在 Activity / Fragment
中获取 View
,进行事件监听
2.通过 View
事件获取数据后进行处理
3.设置处理后的数据给 View
代码如下:
class NormalFragment : Fragment() {companion object {fun newInstance(): Fragment {return NormalFragment()}}private val handler: Handler = Handler()override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.architecture, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)titleText.text = "NORMAL"edit.addTextChangedListener(object : TextWatcher {override fun afterTextChanged(s: Editable?) {handleData(s.toString())}override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}})clearText.setOnClickListener {edit.setText("")}}// 数据的处理,真实情况下可能是网络请求,磁盘存取,大量计算逻辑等等private fun handleData(data: String) {if (TextUtils.isEmpty(data)) {msgText.text = "default msg"return}msgText.text = "handle data ..."handler.removeCallbacksAndMessages(null)// 延迟来模拟网络或者磁盘操作handler.postDelayed({msgText.text = "handled data: $data"}, 3000)}}
默认开发方式的缺点:
我们来分析一下上面的代码,一个明显的特点就是处理逻辑都集中在了 Activity / Fragment
中,不管是对 View
的操作,还是对数据的处理。带来的问题就是 Activity / Fragment
中逻辑臃肿,后续扩展牵一发而动全身。而且职责划分不清晰,给后续维护也带来了困难。
既然如此,我们看看使用架构模式改造后是什么样子的。
五、MVC 架构
5.1 模式介绍
其实关于 MVC
架构,在不同的框架里,实现会有些差别,这也正说明了架构是一种思想。我们这里选用一种比较主流的实现。
5.1.1. 解决什么问题
我们可以看到,上面不使用架构进行开发,带来的问题是 Activity / Fragment 逻辑臃肿,不利于扩展。所以 MVC 就要解决的问题就是:控制逻辑,数据处理逻辑和界面交互耦合。
这里先插一个题外话,其实我们作为程序员,写代码不仅要实现需求,还要让代码易读,易扩展。这一点,往往也能体现功力,并不是说使用了各种奇技淫巧才是大神。
不知道大家是否有接触过 Java Swing 桌面应用开发,在 Java Swing 中,界面 / 控件的设置,也是用 Java 代码来实现的,如果不采用架构,最后的结果就是控制逻辑,数据处理以及页面展示的代码都集中在一个类中,读者朋友们可以想象一下,这样的代码简直是难以维护
5.1.2. 如何划分角色
为了解决上面的问题,MVC
架构里,将逻辑,数据,界面的处理划分为三个部分,模型(Model)-视图(View)-控制器(Controller)。各个部分的功能如下:
Model
模型,负责数据的加载和存储。View
视图,负责界面的展示。Controller
控制器,负责逻辑控制。
5.1.3. 如何通信(数据的流向)
我们再看看三者之间是怎么通信的。
在介绍通信之前,我们先解释一下通信中的数据是什么。其实在 Android 开发中,通信数据可以理解为两种,一种是数据结构,也就是网络请求,本地存储等通信使用的 JavaBean
,另一种是事件,也就是控件产生的动作,包括触摸,点击,滑动等等。我们在通信过程中,也主要关注这两种数据。
在 MVC
架构中,View
产生事件,通知到 Controller
,Controller
中进行一系列逻辑处理,之后通知给 Model
去更新数据,Model
更新数据后,再将数据结构通知给 View 去更新界面。
这就是一个完整 MVC
的数据流向
5.2 在 Android 中的具体实现
理解了 MVC
模式,我们看看其具体实现。
其实在 Android 开发中,其本身默认可以理解为 MVC
结构,把 View
放在 xml
中与 Java
代码解耦,然后 Activity / Fragment
充当 Controller
进行逻辑控制,但是 Android 本身并没有对 Model
进行划分,所以往往我们会让 Activity / Fragment
充当 Model
和 Controller
两个角色。而且往往 xml
中的 View
操作也是在 Activity / Fragment
中,导致有时候 Activity / Fragment
也会充当一些 View
的角色。
所以我们在具体实现过程中,要把职责划分清楚,这里我们让 Fragment
充当 View
的角色,把 Model
和 Controller
的逻辑划分清楚。
我们先定义三个接口如下:
// 数据模型接口,定义了数据模型的操作interface IModel {fun setView(view: IView)// 数据模型处理输入的数据fun handleData(data: String)// 清空数据fun clearData()}// 视图接口,定义视图的操作interface IView {fun setController(controller: IController)// 数据处理中状态fun dataHanding()// 数据处理完成,更新界面fun onDataHandled(data: String)}// 控制器接口,定义控制器的逻辑interface IController {fun setModel(model: IModel)// EditText 数据变化,通知控制器fun onDataChanged(data: String)// 清空按钮点击事件fun clearData()}
上面三个接口分别定义了 Model,View,Controller
的操作。有一点注意的是,根据 MVC
的通信流程,View
需要持有 Controller
,Controller
需要持有 Model
,Model
需要持有 View
,所以需要暴露相应的接口。
下面我们看看具体的实现:
- Model 的实现
Model 中对数据的处理是添加了 "handled data: "
前缀,并增加了 3 秒的延迟
class HandleModel : IModel {private var view: IView? = nullprivate val handler: Handler = Handler(Looper.getMainLooper())override fun setView(view: IView) {this.view = view}// 接受到数据后,进行处理,这里设置了 3 秒的延迟,模拟网络请求处理数据的操作override fun handleData(data: String) {if (TextUtils.isEmpty(data)) {return}view?.dataHanding()handler.removeCallbacksAndMessages(null)// 延迟来模拟网络或者磁盘操作handler.postDelayed({// 数据处理完成,通知 View 更新界面view?.onDataHandled("handled data: $data")}, 3000)}// 接收到清空数据的事件,直接清空数据override fun clearData() {handler.removeCallbacksAndMessages(null)// 数据清空后,通知 View 更新界面view?.onDataHandled("")}}
- Controller 的实现
Controller
的实现比较简单,将操作直接转发给 Model
,实际上,对于复杂的业务场景,这里要处理很多业务逻辑。
class HandleController : IController {private var model: IModel? = nulloverride fun onDataChanged(data: String) {model?.handleData(data)}override fun clearData() {model?.clearData()}override fun setModel(model: IModel) {}}
- View 的实现
这里 Fragment
充当了 View
的角色,主要负责将 View
的事件传递给 Controller
,以及接受到 Model
的数据进行界面更新。
class MVCFragment : Fragment(), IView {companion object {fun newInstance(): Fragment {return MVCFragment()}}private val model: IModel = HandleModel()private var controller: IController = HandleController()override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.architecture, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)setController(controller)model.setView(this)titleText.text = "MVC"edit.addTextChangedListener(object : TextWatcher {override fun afterTextChanged(s: Editable?) {// 通知 Controller 输入的数据产生变化controller?.onDataChanged(s.toString())}override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}})clearText.setOnClickListener {// 通知 Controller 清空数据事件controller?.clearData()}}// Model 数据变化,进行界面更新override fun onDataHandled(data: String) {if (TextUtils.isEmpty(data)) {edit.setText("")msgText.text = "default msg"} else {msgText.text = data}}// Model 数据变化,进行界面更新override fun dataHanding() {msgText.text = "handle data ..."}override fun setController(controller: IController) {this.controller = controller}}
这样我们就实现了一个简单的 MVC
结构。
5.3 MVC 架构模式的优缺点
优点:
- 结构清晰,职责划分清晰
- 降低耦合
- 有利于组件重用
缺点:
- 其实我们上述的示例,已经是经过优化的
MVC
结构了,一般来说,Activity / Fragment
会承担View
和Controller
两个角色,就会导致Activity / Fragment
中代码较多 - Model 直接操作
View
,View
的修改会导致Controller
和Model
都进行改动 - 增加了代码结构的复杂性
六、MVP 架构
6.1 模式介绍
6.1.1. 解决什么问题
MVP 要解决的问题和 MVC
大同小异:控制逻辑,数据处理逻辑和界面交互耦合,同时能将 MVC
中的 View
和 Model
解耦。
6.1.2. 如何划分角色
MVP 架构里,将逻辑,数据,界面的处理划分为三个部分,模型(Model)-视图(View)-控制器(Presenter)。各个部分的功能如下:
Model
模型,负责数据的加载和存储。View
视图,负责界面的展示。Presenter
控制器,负责逻辑控制
6.1.3. 如何通信(数据的流向)
我们可以看到,MVP 中的各个角色划分,和 MVC
基本上相似,那么区别在哪里呢?区别就在角色的通信上。
MVP
和 MVC
最大的不同,就是 View
和 Model
不相互持有,都通过 Presenter
做中转。View
产生事件,通知给 Presenter
,Presenter
中进行逻辑处理后,通知 Model
更新数据,Model
更新数据后,通知数据结构给 Presenter
,Presenter
再通知 View
更新界面。
这就是一个完整 MVP 的数据流向。
6.2 在 Android 中的实现
理解了 MVP
之后,我们看一下其具体实现。
首先我们定义三个接口:
// 模型接口,定义了数据模型的操作interface IModel {fun setPresenter(presenter: IPresenter)// 梳理数据fun handleData(data: String)// 清除数据fun clearData()}// 视图接口,定义了视图的操作interface IView {fun setPresenter(presenter: IPresenter)// 数据处理中视图fun loading()// 数据展示fun showData(data: String)}// 控制器,定义了逻辑操作interface IPresenter {fun setView(view: IView)fun setModel(model: IModel)// Model 处理完成数据通知 Presenterfun dataHandled(data: String)// Model 清除数据后通知 Presenterfun dataCleared()// View 中 EditText 文字变化后通知 Presenterfun onTextChanged(text: String)// View 中 Button 点击事件通知 Presenterfun onClearBtnClicked()}
上面定义了 View,Model,Presenter
三个接口,其中 View
和 Model
会持有 Presenter
,Presenter
持有 View
和 Model
。
接着看下接口的实现:
- Model 的实现
class HandleModel : IModel {private var presenter: IPresenter? = nullprivate var handler = Handler(Looper.getMainLooper())override fun handleData(data: String) {if (TextUtils.isEmpty(data)) {return}handler.removeCallbacksAndMessages(null)// 延迟来模拟网络或者磁盘操作handler.postDelayed({// 数据处理完成,通知 Presenterpresenter?.dataHandled("handled data: $data")}, 3000)}override fun clearData() {handler.removeCallbacksAndMessages(null)// 数据清理完成,通知 Presenterpresenter?.dataCleared()}override fun setPresenter(presenter: IPresenter) {this.presenter = presenter}}
Model
的实现和前面 MVC
中的实现基本一致,不过在 MVC
中 Model
直接操作 View
进行视图展示,而在 MVP
里,要通知 Presenter
去中转。
- View 的实现
这里依旧是 Fragment
充当了 View
的角色,主要负责将 View
的事件传递给 Presenter
,以及接受到 Presenter
的数据进行界面更新。
class MVPFragment : Fragment(), IView {companion object {fun newInstance(): Fragment {val presenter = Presenter()val fragment = MVPFragment()val model = HandleModel()fragment.setPresenter(presenter)model.setPresenter(presenter)presenter.setModel(model)presenter.setView(fragment)return fragment}}var mpresenter: IPresenter? = nulloverride fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.architecture, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)titleText.text = "MVP"edit.addTextChangedListener(object : TextWatcher {override fun afterTextChanged(s: Editable?) {// 传递 文字修改 事件给 Presentermpresenter?.onTextChanged(s.toString())}override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}})clearText.setOnClickListener {// 传递按钮点击事件给 Presentermpresenter?.onClearBtnClicked()}}override fun setPresenter(presenter: IPresenter) {this.mpresenter = presenter}// 展示数据处理中的视图override fun loading() {msgText.text = "handling data ..."}// 展示处理后的数据override fun showData(data: String) {msgText.text = data}}
- Presenter 的实现
这里 Presenter
的实现比较简单,没有太多的业务逻辑,实际应用中,这里会进行业务逻辑的处理。
class Presenter : IPresenter {private var model: IModel? = nullprivate var view: IView? = nulloverride fun setModel(model: IModel) {this.model = model}override fun setView(view: IView) {this.view = view}override fun dataHandled(data: String) {view?.showData(data)}override fun dataCleared() {view?.showData("")}override fun onTextChanged(text: String) {view?.loading()model?.handleData(text)}override fun onClearBtnClicked() {model?.clearData()}}
6.3 MVP 架构模式的优缺点
优点:
- 结构清晰,职责划分清晰
- 模块间充分解耦
- 有利于组件的重用
缺点:
- 会引入大量的接口,导致项目文件数量激增
- 增大代码结构复杂性
七、MVVM 架构
7.1 模式介绍
7.1.1. 解决什么问题
MVVM
要解决的问题和 MVC
,MVP
大同小异:控制逻辑,数据处理逻辑和界面交互耦合,并且同时能将 MVC
中的 View
和 Model
解耦,还可以把 MVP
中 Presenter
和 View
也解耦。
7.1.2. 如何划分角色
MVVM
架构里,将逻辑,数据,界面的处理划分为三个部分,模型(Model)-视图(View)-逻辑(ViewModel)。各个部分的功能如下:
Model
模型,负责数据的加载和存储。View
视图,负责界面的展示。ViewModel
控制器,负责逻辑控制。
7.1.3. 如何通信(数据的流向)
我们可以看到,MVP
中的各个角色划分,和 MVC
,MVP
基本上相似,区别也是在于角色的通信上。
我们上面说到,在 MVP
中,就是 View
和 Model
不相互持有,都通过 Presenter
做中转。这样可以使 View
和 Model
解耦。
而在 MVVM
中,解耦做的更彻底,ViewModel
也不会持有 View
。其中 ViewModel
中的改动,会自动反馈给 View
进行界面更新,而 View
中的事件,也会自动反馈给 ViewModel
。
要达到这个效果,当然要使用一些工具辅助,比较常用的就是 databinding
。
在 MVVM 中,数据的流向是这样的:
View
产生事件,自动通知给 ViewMode
,ViewModel
中进行逻辑处理后,通知 Model
更新数据,Model
更新数据后,通知数据结构给 ViewModel
,ViewModel
自动通知 View
更新界面。
这就是一个完整 MVVM
的数据流向。
7.2 在 Android 中的实现
MVVM
的实现会复杂一点,我们先看下接口的定义:
// ViewModel 接口,定义了逻辑操作interface IViewModel {fun setModel(model: IModel)fun handleText(text: String?)fun clearData()fun dataHandled(data: String?)fun dataCleared()}// 模型接口,定义了数据操作interface IModel {fun setViewModel(viewModel: IViewModel)fun handleData(data: String?)fun clearData()}
MVVM
中的接口只定义了 ViewModel
和 Model
,没有 View
接口,是因为 View
是通过 databind
和 ViewModel
的。
我们再看看具体实现:
- Model 实现
Model
的实现和上面基本一致,就是对数据的处理,处理完成后通知ViewModel
。
class HandleModel : IModel {private var viewModel: IViewModel? = nullprivate var handler = Handler(Looper.getMainLooper())override fun handleData(data: String?) {if (TextUtils.isEmpty(data)) {return}handler.removeCallbacksAndMessages(null)// 延迟来模拟网络或者磁盘操作handler.postDelayed({// 数据处理完成通知 ViewModelviewModel?.dataHandled("handled data: $data")}, 3000)}override fun clearData() {handler.removeCallbacksAndMessages(null)// 数据清理完成通知 ViewModelviewModel?.dataCleared()}override fun setViewModel(viewModel: IViewModel) {this.viewModel = viewModel}}
- ViewModel 实现
ViewModel
的实现要有些不同,我们采用 databind
进行 ViewModel
和 View
的绑定。
其中会定义两个变量,inputText
是和 EditText
双向绑定的数据,handledText
是和 TextView
双向绑定的数据。
当 EditText
中输入的数据有变化,会通知到 inputText
注册的监听器中,而 handledText
值的改变,会自动显示到界面上。
class ViewModel : IViewModel {private var model: IModel? = null// View 绑定的数据,inputText 和 handledText 更新后会自动通知 View 更新界面var inputText: MutableLiveData<String> = MutableLiveData()var handledText: MutableLiveData<String> = MutableLiveData()init {// 注册数据监听,数据改变后通知 Model 去处理数据inputText.observeForever {handleText(it)}handledText.value = "default msg"}override fun handleText(text: String?) {if (TextUtils.isEmpty(text)) {handledText.value = "default msg"return}handledText.value = "handle data ..."model?.handleData(text)}// 清空按钮的点击事件绑定override fun clearData() {model?.clearData()}override fun setModel(model: IModel) {this.model = modelmodel.setViewModel(this)}// Model 数据处理完成,设置 handledText 的值,自动更新到界面override fun dataHandled(data: String?) {handledText.value = data}// Model 数据处理完成,设置 inputText 的值,自动更新到界面override fun dataCleared() {inputText.value = ""}}
- View 实现
看一下View
中的数据绑定。
class MVVMFragment : Fragment() {companion object {fun newInstance(): Fragment {return MVVMFragment()}}override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {// 使用 databind 进行数据绑定var binding: ArchitectureBindingBinding = DataBindingUtil.inflate(inflater, R.layout.architecture_binding, container, false)binding.lifecycleOwner = thisval viewModel = ViewModel()viewModel.setModel(HandleModel())binding.viewmodel = viewModelreturn binding.root}}
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><!--定义 View 中绑定的数据--><data><variablename="viewmodel"type="com.zy.architecture.mvvm.ViewModel" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="10dp"tools:context=".MainActivity"><TextViewandroid:id="@+id/titleText"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="MVVM" /><!--双向绑定 inputText 到 EditText--><EditTextandroid:id="@+id/edit"android:layout_width="match_parent"android:layout_height="50dp"android:text="@={viewmodel.inputText}" android:textColor="@android:color/darker_gray" /><!--绑定 handledText 到 TextView--><TextViewandroid:id="@+id/msgText"android:layout_width="wrap_content"android:layout_height="30dp"android:layout_marginTop="10dp"android:text="@{viewmodel.handledText}"android:textColor="@android:color/darker_gray" /><!--绑定清空数据的点击事件 到 TextView--><TextViewandroid:id="@+id/clearText"android:layout_width="match_parent"android:layout_height="30dp"android:layout_marginTop="10dp"android:background="@color/colorPrimary"android:gravity="center"android:onClick="@{() -> viewmodel.clearData()}"android:text="clear"android:textColor="@android:color/white" /></LinearLayout></layout>
通过上面的实现,当 EditText
中文字变化后,会自动修改 inputText
的值,触发 inputText
监听器,此时 ViewModel
将消息传递给 Model
进行处理,Model
数据处理完成后,通知 ViewModel
更新 handledText
的值,自动更新到界面上。
点击清空按钮时,自动调用绑定的点击函数,通知 ViewModel
清空事件,ViewModel
将消息传递给 Model
进行数据清空,Model
数据处理完成后,通知 ViewModel
进行界面更新。
7.3 MVVM 架构模式的优缺点
优点:
- 结构清晰,职责划分清晰
- 模块间充分解耦
- 在
MVP
的基础上,MVVM
把View
和ViewModel
也进行了解耦
缺点:
- Debug 困难,由于
View
和ViewModel
解耦,导致 Debug 时难以一眼看出View
的事件传递 - 代码复杂性增大
八、架构模式的运用
上面的文章中,我们介绍了 MVC,MVP,MVVM
三种架构模式,以及其简单的实现。这里我们再回过头思考一下,什么时候该使用架构模式呢?
架构模式可以使代码模块清晰,职责分工明确,容易扩展,带来的副作用就是会引入大量的接口,导致代码文件数量激增。
我们在最开始说过,架构模式是用来解决特定的问题的,如果特定的问题在目前阶段不是问题,或者不是主要问题,那么我们可以先不考虑使用架构模式。比如一个功能非常简单,代码量少,而后续又没有扩展的需求,那我们直接使用传统方式进行开发,快速且清晰,完全没有必要为了架构而架构。
对于在开始没有考虑架构模式的代码,后续慢慢去重构,也是一个好的选择。
总结来说就是:架构虽好,可不要贪杯哦~
总结
关于我:
更多面试内容,面试专题,flutter视频 全套,音视频从0到高手开发。
关注GitHub:https://github.com/xiangjiana/Android-MS免费获取面试PDF合集免费提供简历修改建议,获取大厂面试PDF
https://u.wechat.com/ENywrVttLJsE4P0PTa0cnFs (二维码自动识别)
mvvm模式和mvc的区别_Android 开发中的架构模式 -- MVC / MVP / MVVM相关推荐
- 前端开发中的MCRV模式
针对前端开发中基于ajax的复杂页面开发所面临的代码规模大,难以组织和维护,代码复用性.扩展性和适应性差等问题,本文尝试以MVC思想为基础,结合Web前端开发中内容-结构-表现-行为相分离的开发标准, ...
- 游戏开发中的策略模式
游戏开发中的策略模式 博主公司今年的新项目是一个重度养成中度策略的塔防游戏(参考国外的random dice),虽然最后项目算是垮了吧(一测的留存实在太低),但是还是需要总结一下代码(总结才会进步). ...
- MIS开发中C/S模式与B/S模式的结合策略
原文url:http://www.ahetc.gov.cn/cit/199910/03.htm 感觉十分不错,两天后再补充自己的观点 一.引言 Intranet这个名字自Internet商业化以来,已 ...
- android怎么监听多点触摸_Android开发中多点触摸的实现方法
Android多点触控需要LCD驱动和程序设计支持,其实我们只要采用电容屏触摸手机的技术即可,接下来,就让爱站技术频道小编来讲解Android开发中多点触摸的实现方法吧! 多点触摸技术在实际开发过程中 ...
- 什么是DFU模式和什么是DUF模式,有什么区别?ipad如何进入DFU模式和DUF模式?
什么是DFU 可能你听说iPhone的DFU模式, DFU的全称是Development FirmwareUpgrade,实际意思就是iPhone固件的强制升降级模式.例如,在你降级iPhone固件的 ...
- JSP开发中的分层模式
分层模式: 1.分层模式是最常见的一种架构模式. 2.分层模式是其他模式的基础. **目的:**业务处理代码与JSP代码混在一起,不易阅读,不易代码维护. **方式:**将代码根据职责不同,进行分离分 ...
- Jetpack Compose 架构比较:MVP MVVM MVI
本次 I/O 大会上曝出了 Compose 1.0 即将发布的消息,虽然 API 层面已趋于稳定,但真正要在项目中落地还少不了一套合理的应用架构.传统 Android 开发中的 MVP.MVVM 等架 ...
- 重温经典之《企业应用架构模式》——.NET中的架构模式运用 (Base Patterns 1)
今天看看几个基本模式,这包括Gateway模式,Mapper模式,LayerSupertype模式和Separated Interface模式. 在这本书的最后一章,Martin Fowler放了一大 ...
- 软件架构中的架构模式和最佳实践:探索和实践
作者:禅与计算机程序设计艺术 "架构"这个词汇一直是软件工程师们谈论的热点话题之一,无论从代码设计.框架选型.需求分析.项目管理.测试策略还是后续的维护.运维等各个方面都离不开架构 ...
最新文章
- spring官方文档阅读笔记
- 为恶意文件“画像” 瀚思科技基于深度学习技术快速锁定未知威胁
- 使用Managed DirectX编写游戏
- 4月18日 MySQL学习
- 阿里:千亿交易背后的0故障发布
- i5功耗最低的cpu_近年最大飞跃 Intel第11代低功耗酷睿处理器官宣:集显2倍、AI乘4...
- [paper reading] ResNet
- 微软Asp.Net架构与项目团队管理建设模型分析
- DIV+CSS常见问题的14条原因分享
- oracel vm 安装windows server 2012报错Error 0x000000C4
- flyaway mysql_MySQL open table
- TSE无线通信(铺垫)
- 算法提高 解二元一次方程组
- 【FPGA创新设计竞赛——2022紫光同创杯】1、“基于 RISC-V 处理器的软硬件系统设计”赛题介绍
- 商汤研究院基础视觉组正式员工(校招/社招)实习生长期招聘
- 通过python发送邮件
- c语言字符幂函数怎么编写,c语言幂函数_C ++中的幂函数
- Ray Tracing(扩展欧几里得,ax+by=c最小解)
- 大学生实习报告心得三篇
- 改好DEBUG七处缺点的comexe实现报告