写的Android代码不能复用?从MVC开始重新学习

前言

Android项目架构发展了这么多年,MVC,MVP,MVVM,现在又出现了MVI。架构层出不穷,可我一致感觉自己用的不太对。

MVP写的代码好像…和MVC写的差不多。用MVVM写的代码,emm 和之前的好像也差不多

我发现自己有一个能力,网上所有号称可扩展,可复用,可维护,灵活易测试的架构。到了我手里都变得不可扩展,不可复用,不可维护,不灵活,没测试过。 我一点都没有在含沙射影,只是觉得自己很牛逼

本文大概脉络从MVC的概念开始重新学习,讨论Android习惯写法的问题,Android MVC是如何演化到MVP的,讨论MVVM的特点,最终提出一种未实践过的理想写法

Untitled.png

回顾使用MVC的目的

  1. 实现分离
  2. 代码复用

实现分离经过上述讨论可以知道MVC很好的达成了目标。

现在考虑一下代码复用的问题

  1. Model,可以复用。如果有一个项目两个版本的开发经验的同学应该有体会。网络请求,缓存,数据处理等UI无关的业务逻辑是完全可以复用的。
  2. View,可以复用。简单的例子:自定义圆形头像,代码实现之后任意一个位置都可以使用,不用重复自定义过程
  3. Controller,很遗憾,不可复用 。

至少Android中的 Controller 不可复用,因为Controller 是 Activity。Model对象可以任意位置使用,View 也可以任意位置使用。但是Activity不行,它是系统创建的,开发人员无法管理Activity对象。想要复用Activity代码,一般情况下通过继承解决,但是不可能因为复用一段业务逻辑就定义一个抽象Activity。

因此B页面想要复用A页面中的一个加载网络头像功能流程如下:

  1. Model:提供网络头像地址,可复用直接new对象
  2. View:加载网络头像,可复用 在xml声明
  3. Controller:持有Model,View,绑定数据,不可复用 需要从A页面复制组织代码到B页面

到这里原有的AndroidMVC模型有问题,Activity 既是Controller 又是逻辑的调用者,四不像。

看代码

JS 模拟的MVC案例,来自维基百科,结合注释很容易理解。除了Model,View,Controller,还有特别重要的一行,MVC的调用!

意义辨析:

  1. 先有一个需求,加载网络头像
  2. 不使用MVC,所有代码写在一起,代码层次不明显,难维护,无法复用
  3. 使用MVC后,代码分为三部分各司其职互不干扰,三部分代码共同解决需求—加载网络头像。
  4. 当页面A有展示网络头像的需求。页面A在加载时创建Controller对象,调用加载头像的方法。MVC组件自行工作,页面A对接Controller,Controller组织Model,View实现功能。
  5. 按照这种逻辑,页面B有展示网络头像的需求,同样创建Controller对象调用方法即可。实现代码复用

通过对比可以看出Android的MVC模型确实有点毛病,

window.onload 与 activity.onCreate 意义一致,代表页面的加载。

不同点在于JS案例中页面 和 Controller 是两个东西。 Android案例中 页面 和 Controller 是一个东西。

Android的MVC是残缺的MVC,M和V很明确,C模糊不清 或者没有C。所以Android中无法复用很彻底的复用代码。

MVC进化MVP

经过上面的讨论,发现Android中的MVC是残缺不全的,缺少C层。那就造个C层,创造新事物,起新名字,非常自然的MVP诞生了。

在Android中MVP才真正有点MVC的样子。

  1. Model:无变化
  2. View:Activity+XML
  3. Controller:Presenter

MVP把Activity 和 XML 一起当作View,View主要有两点工作

  1. 接收Controller传递的数据,展示给用户
  2. 接收用户交互产生的数据,传递给Controller

这样一来Activity承担的工作就很少了。

Presenter 才是真正 Controller。 持有Model,View,绑定数据,负责UI展示逻辑

Model 一旦确定万年不变

在编写Model 和 Presenter的时候,会有有点难以取舍,不知道什么样的代码放在Model,什么样的代码放在President。一个非常简单的判断方式,任何与UI发生关系的代码都不属于Model。

举个例子,加载用户网络头像

  1. Model:提供网络头像地址
  2. View:加载网络头像
  3. Controller:持有Model,View,绑定数据

如下伪代码所示,Activity 和 Presenter 非常轻,所有的数据逻辑细节都在Model中。这符合MVC的概念,M重,VC轻

MVP如果使用得当足以应付绝大部分开发工作,已经很完美了

MVP进化MVVM

首先需要明确的一点不是使用了 jetpack中的ViewModel组件就叫做MVVM。MVVM标志性特点是数据绑定。

除此之外MVVM与MVP并没有区别

那么什么叫做数据绑定呢/p>

需要用Vue举例,如下代码展示了WebView加载网络页面。

这个需求在Android中实现:

  1. 在xml中声明webView
  2. Activity 通过findViewById() 获取webView对象
  3. 接收其他页面传递参数
  4. webview.setUrl(参数)

在Vue中

  1. webview 绑定变量link
  2. 变量link的值被改变,webView自动刷新 开始工作

数据绑定,数据和UI组件直接绑定,当数据改变后UI组件自动跟着变化,不需要findViewById,setValue这种操作。

Android中findViewById()的开发方式,对应web开发的DOM操作。

Android中实现数据绑定需要使用 jetpack中的databinding组件,databinding只是一个三方库 没办法和vue对标。新出的compose 才可以和 vue对标,声明式UI,数据绑定。

现有写法仍然无法复用

在Android中MVP是完美的MVC,MVVM进一步优化添加了数据绑定,代码分离已经做的很好了,但是仍然无法做到上面展示过的 维基百科JS MVC案例中在任意页面加载Controller的效果

原因在于在Activity,开发人员无法管理Activity对象,只要Controller 或 View 与Activity扯上关系那肯定是无法复用的。

习惯写法MVC层次划分的粒度太大了,什么意思呢/p>

假设如图所示的首页需求:轮播图,功能入口,推荐列表。三个需求的数据全部从接口获取

Untitled 2.png

我个人长久以来都是这种写法,以页面为单位,以Activity为单位,造成的结果就是Model 和 Presenter 只使用 对应的页面。如果其他页面也要用到轮播图组件,Model 可能会复用,但是Controller (Presenter )和 View(Activity) 肯定是要重建的,无法复用。

原因在于以Activity为主的粒度太大了,以此构建的MVC不是MVC三个组件合力完成一个功能,而是把页面整体代码划分为三层,只有代码分离没有复用。

理想的写法

每一个activity,每一个页面看作应用场景。每一个场景下包含许多功能组件,每个功能模块由MVC实现。完成一个页面的功能就好像搭积木一样,按需加载加载功能组件,组件内部自动运行加载数据。

写的Android代码不能复用?从MVC开始重新学习 网络安全学习资料 写的Android代码不能复用?从MVC开始重新学习 微信名片 写的Android代码不能复用?从MVC开始重新学习

来源:QXXXD

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年4月10日
下一篇 2022年4月10日

相关推荐