1. 引言
基于Android开发的移动端APP已被广泛应用在各个领域,不断改变着人们的工作生活方式。在互联网+的时代 [1] [2],Android应用开发技术 [3] [4] [5] 不断革新,Android应用需要更高的开发效率和更小的安装成本才能保持长久的生命力。传统开发过程中,项目模块都位于一个主工程目录下,每个模块之间的隔离不严格,代码调用相对随意。与此同时,开发独立的功能模块时,仍需要在主工程下进行编译调试。传统开发适用于APP功能需求很少的应用,但是当项目体量足够大或是后续业务会逐渐增长,就会出现模块间耦合过高、不易维护、多人协作开发提交代码易产生冲突等问题。若稍微改动一处代码,整个工程需要重新进行编译运行,由于项目工程体量大,编译需要等待的时间将会十分漫长,最终开发的APP所需下载的流量成本也会很高,不利于应用的推广 [6]。因此如何提高开发效率、减少APP安装成本是Android应用开发的首要问题。
周宇等人 [7] 通过Eclipse工具进行Android应用的开发,但是由于Eclipse开发工具的局限性只能使用传统的项目开发方式,当项目业务需求增大,项目内部结构的耦合度便会提高,编译调试时间也将显著增加,对于多人协作开发的中大型项目,开发效率会大大降低。邹绍武等人 [8] 为减少Android应用开发的体量问题,对图片资源的压缩进行了相关研究。殷涛等人 [9] 利用组件化思想将业务模块按照功能进行划分,减少了业务模块间的耦合,但是未结合实际的应用开发场景,对于多人合作开发的效率提升没有显著地提升,也没有考虑到组件间通信路由框架体量大的问题。
综上存在的问题,本文提出一种组件化方案。通过对实际项目进行业务组件划分以提高多人协作开发效率,并利用自定义轻量级组件间通信路由框架ERouter结合资源压缩、选取轻量级第三方库等操作 [10] [11] 对最终业务组件整合后的APP进行深度优化,从而有效地解决Android开发中存在的这些问题。本文以智慧宿管平台开发为例,详细介绍相关技术应用。
2. 移动端设计原理
在移动端应用开发中,移动端设计 [12] 尤为重要,随着项目规模逐渐增加、项目需求与版本不断迭代,整个项目工程便会变得愈加庞大。在开发初期就应具有合理的分析设计,才能应对后期的项目维护与版本迭代。因此,本文提出基于组件化思想 [13] [14] 进行项目开发来解决以上问题。如下将对组件化原理进行分析。
组件化开发原理
在Android开发中主要是通过Android Studio编译工具来实现组件化,每个要划分的业务模块新建成Module并通过编译工具中的Gradle编译插件设置是否能够独立编译运行。在不同的项目场景下,组件划分的方式也不同,目前常见的有从功能进行划分和从业务进行划分的两种组件划分方式。
从功能上划分组件常用于单业务类型项目的开发,如一些工具类的Android应用。通常会将项目划分为用户模块、业务逻辑模块和通信模块。用户模块中具有用户注册、登录、注销和个人信息管理等功能。业务逻辑模块负责具体的业务操作,如查询展示等操作。通信模块负责模块间的交互以及模块的网络通信等。
从业务上划分组件常用于多业务类型项目的开发,其中多业务是指APP中的业务相互独立,交集相对很少。在中大型项目开发中往往需要增加额外的业务,由于划分后业务组件间相互独立,添加新的业务相对便捷。以业务进行组件划分,方便业务复用与业务扩展,这中组件划分方式可有效的提高协作开发的效率。
经过组件划分后,组件化开发框图如图1所示:

Figure 1. Component development block diagram
图1. 组件化开发框图
在实际项目开发中,新建业务功能模块Module时以“app-”为前缀命名,代表该业务功能模块可独立编译运行,而新建核心模块以“lib-”为前缀命名,代表业务功能模块可依赖该核心模块。这种命名形式简洁明了,有利于项目开发维护。其中业务功能模块是具体的业务功能,核心模块为业务功能模块提供基本的数据服务和功能服务,即业务功能模块需要依赖核心模块。依赖关系需要在业务模块对应的Gradle文件中通过“compile project”设置。业务模块的独立运行需要在gradle.properties文件中添加标识moduling,并在相应业务模块的Gradle文件中判断标识,当moduling为true,业务功能模块为application可单独运行,反之为library不可单独运行。
综上,Gradle插件工具实现了项目编译的动态改变。在开发阶段,每个业务功能模块独立运行,每个开发人员负责相应的业务功能模块,做到更深层次的解耦,解决了协作开发的冲突,提高了开发效率。在调试阶段,所有业务功能模块整合成最终的移动应用。通过组件化开发方式,项目进行合理的业务划分,真正实现了高内聚、低耦合,缩短了开发周期。
3. 移动端设计与分析
3.1. 功能分析
本文以智慧宿舍平台为例,APP需实现五个端口,分别为学生端、学工端、后勤端、维修端以及家长端,基本包含了学校管理的所有相关人员,每个端口具有鲜明的业务功能,具体功能框图如图2所示:

Figure 2. Functional block diagram of smart dormitory platform
图2. 智慧宿舍平台功能框图
由于用户需求不断增长,项目内部结构逐渐复杂,应用开发应进行合理的项目设计,从而提高开发效率,降低后期维护和项目迭代的成本。
3.2. 组件化设计与应用
根据本文智慧宿舍平台功能分析,每个端口业务彼此分离明确,业务延伸性较大,选取组件化开发方式代替传统开发方式是项目开发的必然选择。而且各端口间相互独立,因此采用从业务上划分组件方式得到具体组件化流程框图,如图3所示:

Figure 3. Componentized process block diagram
图3. 组件化流程框图
其中app-student、app-manage、app-room、app-repair、app-parent分别代表业务模块学生端、学工端、后勤端、维修端、家长端,app-main模块为启动页功能模块。
通过设置gradle.properties文件中的全局变量moduling为true或false,业务模块中对这个标识做出相应改变,从而改变项目模式为组件模式或集成模式,如学工端模块Gradle文件代码。

从集成模式到组件模式具体在项目中的变化如图4示:


Figure 4. Integration mode and component mode diagram
图4. 集成模式与组件模式图
处于组件模式下,每个业务端口都可独立运行,如图4中右侧图相应业务端口,点击运行即可编译调试。
采用组件化思想,在多人协作开发智慧宿舍平台APP中,每人负责一个业务组件。由于组件间相互独立,因此消除了组件模块间的耦合,大大减少了开发冲突,整合所有组件,就形成了最终的APP,从而缩短了整个项目的任务周期。
3.3. 组件化应用优化
目前,常用的组件化通信路由框架是阿里的ARouter框架,但是该框架功能复杂、体量较大,在只需要简单通信的项目开发中并不适用,而且各业务组件相互独立,在开发过程中容易造成代码冗余等问题,这无疑增加了应用的体量。为解决此问题,本文以智慧宿管平台APP为例进行相应优化,并从APK的构成和具体的优化设计进行研究分析。
3.3.1. APK构成
APK作为项目完成后安装运行的枢纽,其生成过程是应用程序性能优化最终的关键步骤,对于生成APK资源打包过程如图5所示:
针对图5中APK的构成分析具体的资源变化情况,在assets和res文件目录下的资源会直接打包进APK中,其余文件下的资源都会被编译或者被处理成二进制文件,通过Android Studio编译出发布版本APK文件进行解压,由此分析解压后的文件结构,从而找寻可进行APK瘦身的方法,详情见表1:
由表1可知,在项目开发过程中,可以对res目录下的图片资源、classes.dex以及lib下的库所对应的项目目录进行优化。
3.3.2. APK优化设计
通过分析APK结构,本文提出一种APK优化的方案。对于图片资源,在开发中将应用程序内显示的PNG或JPG图片转化为Webp格式,Webp格式的图片保留了JPG和PNG的优点,还能提供更好的有损压缩效果;对于一些简单的图片,完全可以通过drawable中的XML进行绘制;对于classes.dex文件,由于其源头是Java类文件,项目开发中应避免类的重复定义以及无用类的生成,如定义工具类应添加注释,放在Common目录下,这在多人开发项目尤为重要;对于库文件传统做法就是更换体量更小的库,但是很多优秀的库不易替代,或是用来替代的库存在内存泄漏 [15] [16] [17]。
目前,组件化开发中组件间的通信方式主要通过阿里的ARouter路由框架,但是在实际应用场景下,组件间只需要进行简单的通信。此时,ARouter框架体量大的缺点就暴露无疑。因此本文提出一种组件间通信路由框架ERouter,以实现更轻量级的组件间通信,从而进一步降低应用APK的内存。
对于ERouter路由设计描述如下:
步骤一:新建消息中转类ERouter.java用于处理业务模块间的消息跳转,内部维护HashMap来存储消息路由,并通过该类注册路由路径;
步骤二:对于路径类EAction.java,用于实现消息路由的建立和发送消息到具体指定的路由信道,每个业务模块的Activity都应在相应的Action中注册自己的路径;
步骤三:新建消息载体类ERouterRequest.java,其包括消息路径和消息内容,即发送消息实体;
步骤四:当路由消息发送后需要收到反馈,从而使整个链路完整,这里注册ERouterResponse.java里面有相应的状态码以及实体信息;
步骤五:初始化路由,通过ERouter注册所有需要跳转的业务模块路径,并通过抽象路径类EAction去实现具体的业务模块跳转路径;
步骤六:通过ERouter的sendMessage方法进行消息发送,消息实体通过ERouterRequest进行构建,最终通过ERouterResponse完成通信。
核心注册代码如下:

业务模块路由跳转代码如下:


4. 实验研究与分析
为校验ERouter路由框架的效果以及最终组件化应用瘦身的程度,本文通过集成目前最流行准确的Leakcanary框架来检测ERouter路由在业务模块跳转中是否存在内存泄漏,并通过Android Studio自带的Analyze APK工具对APK瘦身优化前后进行分析。
实验环境如下:Windows 7操作系统,Intel(R) Core(TM) i5-3230 CPU @ 2.60 GHa,8 GB内存,编译环境Android Studio3.2,测试机华为荣耀9,6 GB内存,测试如下:
4.1. 组件通信框架内存泄漏检测
本文通过智慧宿管移动端APP学工端入口进入考勤页面点击并跳转到班级详情页面,当点击具体学生时则会跳转到该学生的考勤页面,而学生考勤页面是学生端业务模块的内容,这就完成了一次业务模块间的路由跳转。
使用LeakCanary检测从学工端班级页面跳转到学生端该学生考勤页面,跳转详情如图6所示:

Figure 6. Route jump and memory leak detection diagram
图6. 路由跳转及内存泄漏检测图
由图6可知,从学工端到学生端未检测到内存泄漏证明自定义ERouter路由框架符合开发要求。实验结果表明,本文提出的组件间通信路由框架ERouter完成了项目中对阿里ARouter路由框架的替换,从繁至简实现了开销成本的进一步减小。
4.2. 应用优化检测
通过轻量级组件间通信路由框架ERouter的替换以及相应的资源压缩等操作,得到两个移动端应用APK版本,分别为应用优化前与应用优化后。借助Android studio编译器对release版本的APK进行拆分,使用自带的Analyze APK工具对优化前后的两个APK进行对比如下:
优化前如图7所示:

Figure 7. Analyze the file size of APK before applying optimization
图7. 应用优化前APK解析文件大小图
优化后如图8所示:

Figure 8. Analyze the file size of APK after applying optimization
图8. 应用优化后APK解析文件大小图
由图7、图8可观察到res、lib与class.dex文件的大小变化,实验结果见表2:

Table 2. Comparison table before and after APK optimization
表2. APK优化前后对比表
由以下压缩公式计算优化后的APK优化率:
(1)
其中:InitializedSize为应用优化前APK的大小;CompressedSize为应用优化后APK的大小;CompressedRatio为APK的优化率。
由压缩公式(1)计算可得应用优化的程度为0.448。实验表明:本文提出的轻量级组件间通信路由框架ERouter结合资源压缩等操作有效地减小了应用的体量。
5. 结束语
本文介绍了一种基于Android开发的组件化方案,并将其应用在智慧宿管平台上。通过项目的需求分析,详细介绍了业务组件划分的过程,减小了组件间的耦合,方便了二次开发的功能重用,提高了多人协作开发效率。在项目中集成LeakCanary内存泄漏检测工具,验证了APP界面跳转时自定义组件间通信路由框架ERouter的可用性。并运用Android Studio自带的Analyze APK工具分析该轻量级框架结合资源压缩后智慧宿管应用体量的变化,通过该操作减小了组件化应用的体量,降低了用户的安装流量成本。在今后的工作中,将会继续对组件化方案中组件划分的方式、组件间通信框架以及组件化应用体量的优化进行更加深入的研究,从而更好地应对中大型项目的Android开发。
基金项目
本论文获得了浙江省重点研发计划项目(2020C03094)、浙江省自然科学基金青年基金(2020C03094)、浙江理工大学本科生科研创新计划重点项目(2019ZD-28)以及浙江理工大学本科生科研创新计划一般项目(2019YB-24)的支持。
参考文献