文章目录

  • 一般模式
    • activity_normal.xml
    • NormalActivity
    • Account
    • MCallback
  • MVC
    • MVC简介
    • MVC各层功能
    • MVCModel
    • MVCActivity
    • 优缺点
  • MVP
    • 简介
    • V层
      • IMVPView
      • MVPActivity
    • M层
    • P层
    • 优缺点
    • 使用建议
  • MVVM
    • 简介
    • MVVMModel
    • MVVMViewModel
    • 布局文件
    • MVVMActivity
    • 优缺点
  • 总结

有一个需求:需要查询用户账号信息,用户输入账号,点击按钮可进行查询账号信息,如果查询数据成功,则将数据展示在界面上;如果查询数据失败,则在界面上提升获取数据失败。

一般模式

使用一个Activity完成所有功能
NormalActivity

  • 获取用户输入信息
  • 展示获取信息成功页面
  • 展示获取信息失败页面
  • 查询用户数据
  • 业务逻辑

实现的效果如下,输入用户名,点击提交,查询用户信息,获取信息成功展示成功页,获取信息失败展示失败页。

activity_normal.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><EditTextandroid:id="@+id/userName"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:hint="请输入用户名"android:textSize="14sp" /><Buttonandroid:id="@+id/submit"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="30dp"android:text="提交" /><TextViewandroid:id="@+id/result"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:textSize="14sp" />
</LinearLayout>

NormalActivity

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.juny.mmm.bean.Account
import com.juny.mmm.callback.MCallback
import kotlinx.android.synthetic.main.activity_normal.*
import java.util.*class NormalActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_normal)initEvent()}private fun initEvent() {submit.setOnClickListener {getAccountData(getUserInput(), object : MCallback {override fun onSuccess(account: Account) {showSuccessPage(account)}override fun onFailed() {showFailedPage()}})}}// 获取用户输入信息private fun getUserInput(): String {return userName.text.toString()}// 展示获取数据成功的界面private fun showSuccessPage(account: Account) {result.text = "用户账号:" + account.name + " | " + "用户等级:" + account.level}// 展示获取数据失败的界面private fun showFailedPage() {result.text = "获取数据失败"}// 模拟查询账号数据private fun getAccountData(accountName: String, callback: MCallback) {val random = Random()val isSuccess = random.nextBoolean()if (isSuccess) {val account = Account(accountName, 100)callback.onSuccess(account)} else {callback.onFailed()}}
}

Account

用户信息实体类:使用了 Kotlin 中的数据类来进行实现

data class Account(var name: String, var level: Int)

MCallback

回调接口:对于数据请求的成功和失败提供相关接口

interface MCallback {fun onSuccess(account: Account)fun onFailed()
}

一般模式中,所有的功能都是堆积在一个Activity中的,导致Activity中代码的可复用性降低,Activity过于累赘。


MVC

MVC简介

MVC的全名是Model View Controller,即模型(model)- 视图(view)- 控制器(controller)。


Android的MVC模式中,各个层表示如下:

  • Controller :Activity、Fragment 等;
  • View : layout, view 等控件;
  • Model :数据处理的逻辑,比如:网络请求,数据库,文件查询等。

流程:

  • 对View 进行操作会传递到 Controller 中;
  • Controller 通知 Model后,Model 对数据进行处理,比如网络请求;
  • Model对数据处理完成后,将结果返回给 View 进行展现。

让 Controller 持有 Model的引用;而 Model 要向 View 传递数据一般不会让 Model 持有 View 的引用,而是类似 CallBack 的注册监听的方式进行数据的传递。

MVC各层功能

MVC 主要是把数据处理这块的逻辑给放到 Model 层中进行处理。


代码实现如下:

MVCModel

class MVCModel {// 模拟查询账号数据fun getAccountData(accountName: String, callback: MCallback) {val random = Random()val isSuccess = random.nextBoolean()if (isSuccess) {val account = Account(accountName, 100)callback.onSuccess(account)} else {callback.onFailed()}}
}

MVCActivity

class MVCActivity : AppCompatActivity() {//Activity 中持有 Model 的引用private lateinit var mMVCModel: MVCModeloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_normal)mMVCModel = MVCModel()initEvent()}private fun initEvent() {submit.setOnClickListener {mMVCModel.getAccountData(getUserInput(), object : MCallback {override fun onSuccess(account: Account) {showSuccessPage(account)}override fun onFailed() {showFailedPage()}})}}// 获取用户输入信息private fun getUserInput(): String {return userName.text.toString()}// 展示获取数据成功的界面private fun showSuccessPage(account: Account) {result.text = "用户账号:" + account.name + " | " + "用户等级:" + account.level}// 展示获取数据失败的界面private fun showFailedPage() {result.text = "获取数据失败"}
}

这样我们就将数据请求的部分代码抽离了出去,通过引用进行调用,让代码更加灵活、干净。

优缺点

  • 优点:
    一定程度上的实现了 Model 与 View 的分离,降低了代码的耦合性。

  • 缺点:
    Controller 与 View 难以完全解耦,并且随着项目复杂度的提升,Controller 将会越来越臃肿,Activity 承担了控制器的功能,又要承担部分视图层的工作。

其实 MVC 模式的实现也可以这样进行表示:


这样就体现出来了 View 和 Controller 的耦合关系。


MVP

简介

MVP 的全称为 Model - View - Presenter 模型,他是将 Model 和 View 隔离开来,两者之间不相互作用,而是通过 Presenter 作为一个中间件进行通信;Presenter负责逻辑的处理,Model提供数据,View负责显示。

  • Model: 和 MVC 模式中的 Model 的功能是相同的,主要是做一些数据处理的功能,
  • View:就是直接对应了 Activity,Fragment 以及 layout 和 view 等控件,Presenter 就是他们俩之间沟通的桥梁。这样 Activity 的功能就被简化了,不再充当控制器,主要就是负责 View 层面的工作。
  • 这样我们就可以将业务逻辑处理部分代码从 MVC 中的 Controller 中取出,放入 Presenter 中。

V层

IMVPView

interface IMVPView {fun getUserInput(): Stringfun showSuccessPage(account: Account)fun showFailedPage()
}

MVPActivity

class MVPActivity : AppCompatActivity(), IMVPView {private lateinit var mMVPPresenter: MVPPresenteroverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_normal)mMVPPresenter = MVPPresenter(this)initEvent()}private fun initEvent() {submit.setOnClickListener {mMVPPresenter.getData()}}// 获取用户输入信息override fun getUserInput(): String {return userName.text.toString()}// 展示获取数据成功的界面override fun showSuccessPage(account: Account) {result.text = "用户账号:" + account.name + " | " + "用户等级:" + account.level}// 展示获取数据失败的界面override fun showFailedPage() {result.text = "获取数据失败"}
}

M层

与MVC 中的 Model 的作用相同

class MVPModel {// 模拟查询账号数据fun getAccountData(accountName: String, callback: MCallback) {val random = Random()val isSuccess = random.nextBoolean()if (isSuccess) {val account = Account(accountName, 100)callback.onSuccess(account)} else {callback.onFailed()}}
}

P层

Presenter 持有 View 和 Model 的引用,通过 Presenter 我们向 Model 请求相关数据,并根据判断将结果返回 View 上面显示出来。

class MVPPresenter {private val mView: IMVPViewprivate val mModel: MVPModelconstructor(mView: IMVPView) {this.mView = mViewmModel = MVPModel()}fun getData() {mModel.getAccountData(mView.getUserInput(), object : MCallback {override fun onSuccess(account: Account) {mView.showSuccessPage(account)}override fun onFailed() {mView.showFailedPage()}})}
}

优缺点

  • 优点:
    解决了 MVC 中 Controller 与 View 过度耦合的缺点,职责划分明显,更加易于维护。

  • 缺点:
    接口数量过多,项目复杂的升高。随着项目的复杂度升高, Presenter 层将会越来越臃肿

使用建议

结合上面所说的优缺点,有几条关于 MVP 的使用建议:

  • 接口规范化(封装父类接口以减少接口的使用量);
  • 使用第三方插件自动生成 MVP 代码;
  • 对于一些简单的页面,可以选择不使用框架;
  • 根据项目的复杂程度,部分模块可以选择不使用接口;
  • 其实这些操作都是为了一个目的:减少接口的数量。

MVVM

简介

MVVM 的全称是 Model - View - ViewModel 模型,他的模型结构和 MVP 很相像,但是在代码逻辑上 MVVM 会显得更加简洁,其实他就是将 Presenter 换为了 ViewModel。

MVVM 在 MVP 的基础上实现了数据视图的绑定(DataBinding),这样的话就不用使用接口进行传递了,而是当数据变化的时候,视图会自动更新;反之,当视图发生改变的时候,数据也会进行自动更新。

好处:

  • 减少了接口数量
  • 不用使用 findViewById 去操控 View


首先我们需要在app的 build.gradle 中声明使用 DataBinding

在 android 中添加下面代码

android {dataBinding {enabled = true}
}

使用 Kotlin 的话还需要添加下面代码

apply plugin: 'kotlin-kapt'//需要使用kapt作为注解处理器kapt {generateStubs = true
}

MVVMModel

Model 和 MVP 中的一样

class MVVMModel {// 模拟查询账号数据fun getAccountData(accountName: String, callback: MCallback) {val random = Random()val isSuccess = random.nextBoolean()if (isSuccess) {val account = Account(accountName, 100)callback.onSuccess(account)} else {callback.onFailed()}}
}

MVVMViewModel

分析ViewModel中需要哪些变量以及方法,比如:getData(),需要调用 Model 中的 getAccountData 方法去获取数据,因为我们是使用 DataBinding 方法,所以在 ViewModel 中还需要记录对应的返回值用于展现,因为希望和数据变更进行绑定,防止每次都要更新所有的数据,所以类需要继承 BaseObservable。然后在元素的 get 和 set 方法做出修改,get 方法需要添加注解 @Bindable 而 set 方法中需要加入更新该元素显示的代码 notifyPropertyChanged(BR.XXX); ,BR 是什么呢,其实就是相当于 R 文件,用来确定是那个控件需要更新,只不过这里可以直接用变量名。

class MVVMViewModel : BaseObservable() {private val mvvmModel: MVVMModel = MVVMModel()@get:Bindablevar userInput: String? = nullset(userInput) {field = userInputnotifyPropertyChanged(BR.userInput)}@get:Bindablevar result: String? = nullset(result) {field = resultnotifyPropertyChanged(BR.result)}fun getData(view: View) {this.userInput?.let {mvvmModel.getAccountData(it, object : MCallback {override fun onSuccess(account: Account) {result = "用户账号:" + account.name + " | " + "用户等级:" + account.level}override fun onFailed() {result = "获取数据失败"}})}}
}

布局文件

将 ViewModel 作为布局文件的参数,在布局文件中进行调用。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variablename="viewModel"type="com.juny.mmm.mvvm.MVVMViewModel" /></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><EditTextandroid:id="@+id/userName"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:hint="请输入用户名"android:text="@={viewModel.userInput}"android:textSize="14sp" /><Buttonandroid:id="@+id/submit"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="30dp"android:onClick="@{viewModel.getData}"android:text="提交" /><TextViewandroid:id="@+id/result"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="10dp"android:text="@{viewModel.result}"android:textSize="14sp" /></LinearLayout>
</layout>

MVVMActivity

绑定数据,修改原有的 setContentView 方法,改为使用 DataBindingUtil.setContentView 方法进行绑定,然后我们将我们需要的 ViewModel 传入进去。
DataBinding 有单向绑定和双向绑定的区别,如果是单向绑定的话就是直接用 @{XXX} 的形式,如果是需要双向绑定的话就是需要改为 @={XXX} 的形式。
双向绑定的好处就是不仅在数据变化的时候进行刷新 View,也会在 View 主动修改数据的时候对数据进行更新,多用于编辑框等控件。

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.juny.mmm.R
import com.juny.mmm.databinding.ActivityMvvmBindingclass MVVMActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)var binding = DataBindingUtil.setContentView<ActivityMvvmBinding>(this, R.layout.activity_mvvm)var mvvmViewModel = MVVMViewModel()binding.viewModel = mvvmViewModel}
}

优缺点

  • 优点:
    实现了数据和视图的双向绑定,极大的简化代码

  • 缺点:
    Bug 难以调试,学习成本较大。

总结

框架名 总结
MVC 学习简单,但是解耦不够彻底
MVP 解耦更加彻底,学习起来较为简单,但是代码相对较为繁琐
MVVM 代码逻辑简洁,但是学习成本较大

Android开发中MVC、MVP到MVVM演化相关推荐

  1. Android 开发架构-MVC MVP MVVM详解

    何为架构 架构,即程序的逻辑组织结构,是指导开发过程中划分程序逻辑模块的关键,好的架构要使程序达到高内聚低耦合的设计目标.例如一个人,身体的骨骼即为身体的架构,有了基本骨架之后,才可以决定在头颅里开发 ...

  2. android中的mvp模式怎么定义,详解MVP模式在Android开发中的应用

    一.MVP介绍 随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Mode ...

  3. MVC, MVP 与 MVVM

    前几天读了阮一峰老师的文章<MVC,MVP 和 MVVM 的图示>,觉得讲得十分清晰,所以在这里做一波复习和总结. MVC, MVP 与 MVVM 是三种常见的软件架构,它们之间的特点与区 ...

  4. Android开发中dip,dpi,density,px等详解

    Android开发中的各种单位的解释 Px (Pixel像素) 也称为图像元素,是作为图像构成的基本单元,单个像素的大小并不固定,跟随屏幕大小和像素数量的关系变化(屏幕越大,像素越低,单个像素越大,反 ...

  5. Android开发中应避免的重大错误

    by Varun Barad 由Varun Barad Android开发中应避免的重大错误 (Critical mistakes to avoid in Android development) A ...

  6. android 4.4 禁止下拉,Android开发中禁止下拉式的实现技巧

    我们开发项目的时候,经常会看到禁止的情况,而Android开发中并没有直接调用的接口,下面是爱站技术频道小编就给大家介绍的Android开发中禁止下拉式的实现技巧,希望网友们喜欢! 分享给大家供大家参 ...

  7. 史上最全Android开发中100%会用到的开源框架整理(1/5)

    其实这个开源框架整理很久了,只是一直放在有道云笔记里面,笔者还有很多写得文章都放在有道云笔记里面,有时间都好好整理一下放出来,本篇文章也会不定期更新,由于整理的开源框架分类都有200多个,所有这次只将 ...

  8. Android开发中使用七牛云存储进行图片上传下载

    Android开发中的图片存储本来就是比较耗时耗地的事情,而使用第三方的七牛云,便可以很好的解决这些后顾之忧,最近我也是在学习七牛的SDK,将使用过程在这记录下来,方便以后使用. 先说一下七牛云的存储 ...

  9. 5 个 Android 开发中比较常见的内存泄漏问题及解决办法

    Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要再 ...

最新文章

  1. Android开发神器:OkHttp框架源码解析
  2. 07/11/20 资料整理
  3. excel中如何et vb根据数据自动生成表格_如何实现excel与PPT互联互通(动态生成PPT)...
  4. Oracle 排序中使用nulls first 或者nulls last 语法
  5. 通过 .htaccess 实现缓存策略
  6. extjs之TypeError: d.read is not a function解决方案
  7. Live meeting+OCS 二次开发手记
  8. 麦克风设计指导与选型参考
  9. leetcode 279. 完全平方数(dp)
  10. 前端学习(2026)vue之电商管理系统电商系统之实现分页功能
  11. 2020班徽设计图案高中计算机,高铁工程学院举办2020级班徽设计大赛
  12. 兼容IE和FF:获取Referer的JS和PHP方法 及 PHP利用curl伪造IP和来路
  13. 深度克隆对象【前端每日一题-19】
  14. 使用注解方式搭建SpringMVC
  15. 鸿蒙系统u盘制作,WINDOWS系列 篇二:【保姆级】Windows 10安装版原版系统U盘制作及系统安装教程...
  16. 计算机用户目录是什么,c盘里面users是什么文件夹
  17. 有关H5第八章的页面布局与规划介绍
  18. c语言如何画简单图形,如何用C语言画基本图形
  19. 实例分析!如何快速搭建OA办公系统
  20. 20条技巧,让Chrome超越Firefox (2010-11-16更新)

热门文章

  1. 德源希望教育救助中心第十所希望小学落户河北省涉县
  2. 根据出生日期,得出年龄
  3. 2022-2023第一学期微信小程序期末实训报告
  4. FFmpeg之ffprobe
  5. Ubuntu 18.04 安装最新版本wine(支持微信、企业微信)
  6. ORA-01034:oracle不可用 的解决方法
  7. python3.6爬虫源代码_基于Python3.6爬虫 采集知网文献(更新)
  8. 七分养护三分维修 关注车辆的生命周期保养
  9. MISCONF Redis is configured to save RDB snapshots~
  10. C语言趣味小游戏——猜数字(1到100之间)