借一个项目谈Android应用软件架构,你还在套用MVP 或MVVM吗

简介: 借一个项目谈Android应用软件架构,你还在套用MVP 或MVVM吗

 在《Android开发进阶,从小工到专家》一书的第26页中有这么一段话,说Android之父Andy Rubin在被采访时说过,在设计Android之初他就希望Android能像FaceBook那样可以使用不同的应用中的功能模块儿,通过现有的模块儿像搭积木一样方便地构建一个应用。正式基于这一理念,Android被设计为高度组件化、可复用的系统。


在Android的应用开发中,目前流行MVP和MVVM的软件架构风格,让UI层和业务逻辑层,数据层充分解耦,充分分离。这本来是好事,本文要探讨的本意非是摒弃MVP或MVVM架构,而是意在说明,一切都是根据需要为目的,而不是像做物理题一样的套用公式。意在突出一种模块化和组件化的软件开发思想,助力敏捷开发,大幅度的提高开发效率和稳定性。站在模块化思想的思维角度上是思考和解决问题。而实际的本质上,也是做到了UI和业务逻辑的分离。只是看问题的维度不同。相比之下模块化则是更进一步。因为也能从模块化的思想中找到MVC的影子,显示模块就是V,业务模块就是M。 只是模块化思想来的更细,更容易复用,更实用。M可看做为,又进一步细化的不同的业务逻辑模块组成。至于那个C嘛,算是链接V和M的桥梁。


   金庸武侠小说《笑傲江湖》中,独孤老前辈教令狐冲武功时,教他说忘掉之前那种种花枝招展的帅气姿势吧,别忘了你的目的是什么,只有能够打败对手就是好招。再借用一句马列主义的哲学来说,实践是检验真理的唯一标准。用邓大人的话通俗点儿来说,不管黑猫白毛,能抓得住老鼠就是好猫。意思都是说要告诉我们一是思想不要过于固化和死板,二是真理来自于实践中,而非尽信专家或权威,或是人云亦云。所谓的专家都是有专有家。在家里(某一领域)比较专注(专一某个领域且达到一定境界)。说以专家的告诫都是有一定道理的,但也并非都是真理。毕竟都是人嘛,都不是神仙。最明显的例子就比如说在经济领域,有很多的专家,结果谁都不能百分百预测未来经济的走向,预知哪只股票是潜力股。为什么?因为他们各有各的理。真理只能交给时间和实践来检验。


    再来说说流行的MVP或MVVM架构模式的本意。只有站在更高的维度上去看问题,才能看透问题的本质,否则就会是“不识庐山真面目,只缘身在此山中”。先说如果没有MVP和MVVM这种架构风格之前是什么样,再说它的出现解决了什么问题,有什么好处,以及为什么要用吧。在Google刚推出android应用开发时,第一批吃螃蟹的人,也就是最早的布道者,大都是看官方文档或历程一路摸爬滚打,总结而来的经验。常规和简单的实现业务应用的办法是直接在activity里直接写代码,因为直观且清晰嘛。但是随着业务越做越大,越做越复杂,发现一个activity(UI层)里好几千的代码,看着都费劲,更别提让别人维护了。还有就是换了一个项目,UI变动了,但原来写好的业务都在UI里,从头再做一遍吗?原来做过的有,就费事儿点儿一点点抠出来吧,累死个人了。你说他复用代码了吗?确实复用了,但是很累很繁琐,把原来的业务抽离出来不亚于从头重新实现了一遍业务,且很容易出错。这样的业务充斥在UI层中到处穿插,不但逻辑不清,复用困难,且容易导致各种各样的问题。于是MVP模式出现了。MVP中的p就像个中间人。把M数据模型层或业务层跟这个V,UI层彻底隔离了。无论你的业务是操作数据库或是获取网络数据再怎么加工处理,要想表达给UI层,只能通过P这个中间人去做。这样的好处,一方面业务逻辑清晰,分工明确。一方面利于更大限度的复用。


 但是大道理人都懂,你要是硬是去这么的套公式吧,有时候也很累很纠结。且往往掌握不好度,比如过度的设计,到处是接口,写起来也很累。比如业务逻辑层是放在model层呢还是P层呢,model层是不就是指存取或读取网路或本地数据呀。没人能准确的分清,于是不纠结了咋样顺咋样来,不去较真儿了。


 前面说了一堆废话,现在进入正题。


     先抛出来一个问题,如何在两周内实现一款Android的POS机应用?有刷卡,有语音,有存储,有界面,有通信,有业务。


      是的,没错,是两周的时间功能完整的做出来。


 再思考一个问题,平时小朋友们都爱玩一种搭积木的游戏,为什么他们能够仅凭自己的想象力就能创造出那么多的模型?有桥梁、有大门、有城堡、有汽车、有飞机,想到什么就能快速的搭建起来?其实就是模块化的思想。可惜我小时候只玩过泥巴,想来现在的小朋友们应该更聪明吧。不用管这积木是谁造的,怎么造的,用的什么料。只管搭建自己想要的模型即可。那么,回过头来看我们的软件工程项目开发,何尝灵感不是取自于大自然,取自于日常生活。就比如建造房子,你会去想一块儿砖,一扇窗户是怎么造的吗?每个人各有分工,角色不同,分工不同,共同有序的构建起整个大厦。同样的砖头,放在城市里是建筑,放在农村里可以是墙头。放在我桌子下面,可以垫桌子腿。放到美女口袋里,可以当防色狼武器。同样的模块可以用在各个地方去。根据你的需求,哪有需要往哪搬。


 到这里真正引申出本文的主题,即采用模块化的思想去考虑我们的Android应用,而非死板的套用MVP或MVVM风格。以模块化和组件化的思想去考虑问题,是站在了更高一层的维度上去思考问题。管你是什么设备,什么型号机器,我的本意就是实现这么一套功能。根据需求,把我们的应用拆分为不同的组件和模块。在Android这种机器中,界面,即activity,即MVP中的V视图层,只是我应用中的一个显示UI显示模块儿而已。既然只是占比很小的一个显示模块儿而已,注定业务不会在activity里去写去实现。


 按照模块化的思想来划分的话,一款Android的pos机无非有以下几大模块功能组成而已。


界面UI显示模块,记录存储模块,参数配置文件操作模块,通信模块,语音播报模块,卡操作模块,算法模块(常用加密算法或工具类)等几大模块组成。然后基于这些模块,再在这些模块的上层拆分和建立几个任务去衔接和组织业务。如卡处理任务线程,通信任务线程,定时任务线程等。再利用Android的事件总线通信机制,如rxbus或Eventbus等,把具体业务和UI模块(activity)衔接起来。这不就是完整的应用吗?且结构清晰,分工清晰,全都是模块儿化,一层层的往上搭建应用,是不是很像是搭积木?也完全符合设计模式的几大原则,做到高内聚底耦合。单一职责,接口隔离,开放封闭,迪米特法则。构建的这些基础模块之间,做到相互的独立和无依赖,就最大限度的提高了复用性和稳定性。且结构和逻辑,层次清晰。那么基于这些模块构建的应用之间如何传递数据呢,看下面的图,更清晰直观点儿。



卡操作模块、通信模块、存储模块、语音模块、常用算法或类库等,这些作为底层的基础技术组件用。这些基本都是能够复用的功能独立的模块。


然后在这些可复用的技术组件之上是业务的组织。称之为可复用的业务组件层。模块化的思想有两种,不但是技术组件的模块化,不同的业务之间也可以把独立的业务模块化。目的都是为了结构职责清晰,更大限度的复用,提高稳定性和生产力。比如可以封装出不同的业务模块,交通部卡处理模块,自发卡处理业务模块,二维码业务处理模块,小键盘处理模块,消费记录通信组包和解析等通信业务模块。这些都是可复用的业务组件。那么上层的卡任务和通信任务等可以调用这些业务模块完成整个业务逻辑。


在这些业务模块之上又创建了几个线程任务去组织和衔接业务,各干个的活。跟卡相关的都在卡任务线程里。跟后台通信上传记录和下放参数相关的都在通信线程任务里,需要定时执行的一些其他任务在定时任务线程里。这部分可以看做是业务的大体框架。


最上层就是最接近用户的UI显示层了。需要更新UI时,业务框架层只需要通过事件消息总线技术,把事件通知给UI层处理即可。在UI层可以完成界面展示,页面跳转和切换,以及用户触摸事件等简单的业务逻辑处理。


最后在说下,底层的业务和上层UI,交互的数据从何二来?如何交互,如何传递数据呢,全局的静态类或JavaBean就派上了用场,他们相当于全局变量一样,负责收集和获取数据。至于这数据怎么个显示给UI,何时触发,由业务逻辑层负责触发事件,通过消息总线去通知UI更新或显示,更新或显示的内容在全局的静态类里。


这种模式,如果非要向MVP和MVVM的风格架构上套,它哪个都不是。好像是只有V和M,其他的找不到了。但业务没在V中。总之不要去纠结这究竟是什么路数了。因为一开始考虑问题和看问题的角度就不同,是按照模块儿化思想考虑的。activity只是模块化中的UI模块而已。所以还是不要去往MVP或MVVM上想,不是一回事,忘掉他们吧。


 有了这些之后,大体框架已经有了,接来下就可以专注于业务实现啦。岂不是很简单。两周的时间去完成一些基础业务也是绰绰有余的。但是前提是,建立在这些可复用的技术组件之上。比如通信模块,记录存储模块。记录存储模块本来是操作数据库,但是封装后让你看出来任何数据库操作的影子。只有save和read,delet等简单的接口。把数据模块封装的就像是操作快递存储柜,应用的人只需要知道存东西,存在哪。取东西,东西在哪即可。管你内部是操作的oracle还是MySQL还是sqllite,好的封装尽可能做到迪米特法则。最好让使用者不用去关注你的底层是用什么实现的。


 所以公司新的Android的pos机,我几乎只用了两周时间就搞出来了。是的,两周,这没有开玩笑。


当然这得益于之前711机器累积的经验,提前实现了记录存储模块,通信模块和配置文件操作模块。同时多亏同事的帮忙,分工合作,同事提供卡操作模块的操作卡片的底层接口,美工提供了UI素材。没有这些,一个月也搞不定啊。但是存储模块,由于涉及到记录安全,显示尤其重要。不经过压测是万万不行的,得确保无一条数据丢失。有的说存储数据多简单啊,操作数据库一个 insert指令就完了的事。但是我想说的存储模块是包含了业务的实现。有哪些业务呢,首先,不用再考虑如何建表结构,数据不会一直往下存储,终端机器里敢一直这么傻瓜式的存下去,机器早晚要存满挂掉。记录上送至后台一条,要删除一条,可不是真正的删除啊, 那么岂不很不安全。只是清掉更新标记,即记录是循环覆盖的模式存储。这里面涉及不少业务逻辑,可不是简单的insert和delte就完事了。那么这样封装后使用起来有多简单呢,可以说是傻瓜式操作,谁都会用。即便不知道SQL是啥玩意儿的都能玩的转。保存数据直接 save( data内容)即可。 data内容为要组织的记录的二进制数据。有的说那要强大的sql有啥用,你当成文件存储来用了吗。sql和数据库的优势木发挥出来。这里我只想说SQL是强大,但是你会用高射炮去打蚊子吗。满足需要才是目的。我在终端上压根用不到负复杂的查询。要保存的记录字段有很多,且终端需求上经常多变,会为了哪天需求要求多传个字段,就去动一动表结构吗?太没必要了。那样就太累了。还是那句话,实践出真知,不信撸起袖子来干,不服来战。可以比一下你用操作SQL快还是我经过封装过之后的使用快。我这读写和操作记录只需要几分钟。但是你要提出来给你个卡号,给我找出来他的所有明细,且金额低于10块的,再统计出总额,再关联查询下是是属于哪个司机消费的,那么不好意思,这就得花点儿时间了。不像你一个SQL语句分分钟钟搞定了。但是终端上没有这种需求。即便有,再封装出个接口就行了。内部实现我也用SQL,它的强大是无疑的。


再举例说下配置文件存储模块的封装,假如有个需求让你存储配置信息如 IP和端口 port到配置文件中。你操作完成这些如何做,需要多久?我给你说我需要30秒足够了。这这取决于我打字的快慢。无论你是操作ini文件或是json文件或是xml文件,再怎么也需要额外好多步吧。就拿Android中的 SharedPreference类来说,那么完成这些操作,你需要:


SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
String ip = "218.28.111.121";
int port  = 5050;
sp.putString("IP",ip);
sp.putInt("port",port);


存储完开机要用到的话,还得一个个的加载出来。比如


String ip = sp.getString("ip","");


而我只需要


syscfg.ip = "218.28.133.181";
syscfg.port = 22288;


syscfg.save();即可完成存储。开机后,只需要syscfg.load()即可完成加载。


从这些数据存储量小时,看不到优势多明显。如果有几个个参数要存储和保存呢。优势就出来了。


比如终端要保存票价信息,参数太多了。


dealCfg.ver = 12;
 dealCfg.time = "201910251551";
 dealCfg.discInfo[0].cardType = 5;
 dealCfg.discInfo[0].purseDisc = 100;
 dealCfg.discInfo[1].cardType = 6;
 dealCfg.discInfo[1].purseDisc = 200;
 dealCfg.saveCfg();即可。


最后再来说下复用性。


假如我有另外一项目,也是Android系统,但卡处理部分硬件变了。那么上述只需要改动卡操作模块。其他完全不变,不受影响。假如有另外一Android项目,不涉及到读卡。那么通信模块和存储模块和工具类模块则是直接可以拿走用的。


如果,想在电脑上实现这么一款POS机咋办?


那么业务部分是不需要动的,卡操作模块改变下,换成操作读卡器模式。界面部分,则可以替换为其他的UI或者网页也可以。比如用前端技术Vue或reaect构建出界面作为UI层。使用websocket和卡处理任务交互起来,卡交易成功后通过websocket通知到前端浏览器,javascirpt操作数据去更新UI。


相关文章
|
1天前
|
搜索推荐 开发工具 Android开发
打造个性化Android应用:从设计到实现的旅程
【10月更文挑战第26天】在这个数字时代,拥有一个能够脱颖而出的移动应用是成功的关键。本文将引导您了解如何从概念化阶段出发,通过设计、开发直至发布,一步步构建一个既美观又实用的Android应用。我们将探讨用户体验(UX)设计的重要性,介绍Android开发的核心组件,并通过实际案例展示如何克服开发中的挑战。无论您是初学者还是有经验的开发者,这篇文章都将为您提供宝贵的见解和实用的技巧,帮助您在竞争激烈的应用市场中脱颖而出。
|
2天前
|
存储 Dart 前端开发
flutter鸿蒙版本mvvm架构思想原理
在Flutter中实现MVVM架构,旨在将UI与业务逻辑分离,提升代码可维护性和可读性。本文介绍了MVVM的整体架构,包括Model、View和ViewModel的职责,以及各文件的详细实现。通过`main.dart`、`CounterViewModel.dart`、`MyHomePage.dart`和`Model.dart`的具体代码,展示了如何使用Provider进行状态管理,实现数据绑定和响应式设计。MVVM架构的分离关注点、数据绑定和可维护性特点,使得开发更加高效和整洁。
137 3
|
3天前
|
算法 Java 数据库
Android 应用的主线程在什么情况下会被阻塞?
【10月更文挑战第20天】为了避免主线程阻塞,我们需要合理地设计和优化应用的代码。将耗时操作移到后台线程执行,使用异步任务、线程池等技术来提高应用的并发处理能力。同时,要注意避免出现死循环、不合理的锁使用等问题。通过这些措施,可以确保主线程能够高效地运行,提供流畅的用户体验。
10 2
|
7天前
|
Java API Android开发
安卓应用程序开发的新手指南:从零开始构建你的第一个应用
【10月更文挑战第20天】在这个数字技术不断进步的时代,掌握移动应用开发技能无疑打开了一扇通往创新世界的大门。对于初学者来说,了解并学习如何从无到有构建一个安卓应用是至关重要的第一步。本文将为你提供一份详尽的入门指南,帮助你理解安卓开发的基础知识,并通过实际示例引导你完成第一个简单的应用项目。无论你是编程新手还是希望扩展你的技能集,这份指南都将是你宝贵的资源。
30 5
|
7天前
|
移动开发 Dart 搜索推荐
打造个性化安卓应用:从零开始的Flutter之旅
【10月更文挑战第20天】本文将引导你开启Flutter开发之旅,通过简单易懂的语言和步骤,让你了解如何从零开始构建一个安卓应用。我们将一起探索Flutter的魅力,实现快速开发,并见证代码示例如何生动地转化为用户界面。无论你是编程新手还是希望扩展技能的开发者,这篇文章都将为你提供价值。
|
6天前
|
前端开发 JavaScript 测试技术
Android适合构建中大型项目的架构模式全面对比
本系列教程详细讲解 Kotlin 语法,适合需要深入了解 Kotlin 的开发者。快速学习 Kotlin 语法的小伙伴可以查看“简洁”系列教程。此外,教程还对比了多种适合中大型项目的架构模式,如 MVVM、MVP、MVI、Clean Architecture 和 Flux/Redux,帮助开发者根据项目需求选择合适的架构。
16 3
|
23天前
|
缓存 搜索推荐 Android开发
安卓开发中的自定义控件实践
【10月更文挑战第4天】在安卓开发的海洋中,自定义控件是那片璀璨的星辰。它不仅让应用界面设计变得丰富多彩,还提升了用户体验。本文将带你探索自定义控件的核心概念、实现过程以及优化技巧,让你的应用在众多竞争者中脱颖而出。
|
23天前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
84 1
|
1天前
|
存储 IDE 开发工具
探索Android开发之旅:从新手到专家
【10月更文挑战第26天】在这篇文章中,我们将一起踏上一段激动人心的旅程,探索如何在Android平台上从零开始,最终成为一名熟练的开发者。通过简单易懂的语言和实际代码示例,本文将引导你了解Android开发的基础知识、关键概念以及如何实现一个基本的应用程序。无论你是编程新手还是希望扩展你的技术栈,这篇文章都将为你提供价值和启发。让我们开始吧!
|
24天前
|
Web App开发 安全 程序员
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
多年的互联网寒冬在今年尤为凛冽,坚守安卓开发愈发不易。面对是否转行或学习新技术的迷茫,安卓程序员可从三个方向进阶:1)钻研谷歌新技术,如Kotlin、Flutter、Jetpack等;2)拓展新功能应用,掌握Socket、OpenGL、WebRTC等专业领域技能;3)结合其他行业,如汽车、游戏、安全等,拓宽职业道路。这三个方向各有学习难度和保饭碗指数,助你在安卓开发领域持续成长。
54 1
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势