得到安卓客户端的工程架构实践(得到app运营模块)
liuian 2025-04-30 18:01 70 浏览
一、组件化拆分
组件化的概念其实理解上很简单,所谓组件化,就是把一个功能完整的app拆分成多个子模块,每个子模块可以独立编译和运行,也可以将这些子模块任意组合成一个新的app,子模块之间不互相依赖,但可以相互交互。
1.单体工程架构
一般app的开发早期,团队的重心并不在开发架构的选型上。主要也是因为早期的项目比较小,大家更关注多快好省的完成任务,对于如何复用,如何解耦没有过度考虑。如下图是得到早期的工程架构。
随着版本迭代,app的功能越来越多,项目结构逐渐也演变成了一个庞大的单体工程,内部依赖错综复杂。
当然,这会带来很多很多问题。
第一、逻辑复杂,不易理解。想要熟悉掌握所有功能需要耗费大量的时间和精力,不仅如此,对于新人熟悉业务来说,也会给他们带来巨大的挑战。
第二、不同的业务功能耦合严重。导致面对一个修改,我们无法界定它的影响范围,牵一发,动全身。
第三、构建时间越来越长,降低了研发效率。
2.单体工程组件化拆分
为了解决单体工程存在的这些问题,我们开始了工程的组件化改造。优先梳理各个业务模块,将不同业务模块的代码和资源放到不同的业务子工程中,这些作为组件化工程中的业务组件。对于不同业务组件之间公用的代码和资源,下沉到基础子工程中,作为业务子工程的依赖。独立壳工程app,它的主要任务是负责组件的集成打包,所以尽量不要包含业务逻辑。组件化拆分如下图:
3.组件间通信
工程组件化拆分结束后,我们遇到的另一个问题是如何进行组件间的方法调用,因为业务组件之间是完全解耦的,所以不能简单的通过引用的方式进行调用。
我们为业务组件之间通信提供了两种方式。页面路由和服务调用。从实现上来说,这两种方式都是遵循协议下沉的原则,将服务协议下沉到通信组件。
app启动后,组件工程分别将自己提供的服务和页面路由注册到通信组件。如果某个组件希望调用其他组件提供的服务或路由到其他组件,就可以通过查询通信组件中的注册信息,完成组件间通信的任务。
4.组件单独调试运行
如果我们集成所有组件构建项目,时间会很长,平均大概10分钟左右,为了解决这个问题。我们提出了单组件调试运行的方案。
通过自定义组件构建脚本,每个业务组件都可以作为壳工程独立运行。并且可以集成其他依赖的组件并进行组件间通信。通过这种方式,编译效率得到了很大的提升,我们运行单组件工程,构建时间只需要40秒左右。
5.组件化2.0
组件化用了大概一年时间,我们遇到了新的问题。大家有时希望全组件集成运行app,正如之前的解决方案,我们并没有针对这种情况的优化手段,所以就导致了每天还是浪费了很多时间在编译构建上。
其实,gradle在构建项目时,确实是支持增量编译的,但有时改动一个文件,会导致项目构建时间超过10分钟。我们需要尽快解决这个问题,不然每天团队所有人在构建上浪费的总时间,我粗略的算了下7个人5次10分钟,超过5个小时,还是比较吓人的。
6.全组件集成构建流程分析
下图简要的描述了我们集成构建app的时候需要执行的核心环节。通过分析,我们发现构建时的一些问题。每次编译项目,所有组件工程都会重新执行同样的编译构建流程,所以,如果组件集成可以直接使用aar的方式,那么这些执行的重复构建就可以节省下来。编译时间上会有很大的提升
7.组件打包aar
所以,顺着前面的思路,我们构建了一套完整的组件打包体系。
CI负责实时监控 git 仓库代码变动,当开发人员提交了代码,CI 自动开始执行组件打包脚本。打包脚本会分析出所有包含代码变动的组件,并计算出组件对应的版本和maven仓库信息。使用这些信息,执行每个组件的 gradle 打包任务,并将打包成功后的产出物 aar 上传到组件仓库。
8.组件化2.0集成构建
组件有了aar的管理方式,我们的全组件集成构建逻辑就可以进一步得到升级。
执行全组件集成构建时,首先解析工程下的组件化配置文件。该配置文件中明确标明了某个组件的依赖方式是aar还是源码,及aar的依赖版本和仓库信息。然后构建脚本就会根据这些信息,灵活的配置组件依赖并集成构建app。
使用aar的集成方式,避免了组件的再次编译,全量编译时间从之前的10分钟降低为现在的2分半左右。
二、MVVM 开发架构
这部分,主要包含一些我们在选型开发架构上的心得和实践。如下图描述,工程组件化架构搭建完成后,我们的编译效率和项目管理方式得到了很大的改进。
但是,组件内的业务开发还在采用比较粗放的模式。Controller作为业务功能组织的核心,完成了大概80%的工作量,内部耦合十分严重,极大的限制了代码的复用能力,导致研发效率低下。
1.MVC VS MVP
为了解决目前以Controller为核心的开发模式带来的代码复用问题,我们对比了常见的三种MVX 架构。
其中,MVC 是开发gui应用程序的经典架构。但是,由于Controller直接持有了View的引用并使用这些引用组织展现逻辑,导致展现逻辑不能很好的被复用。
MVP的出现很好的解决了MVC中展现逻辑不易复用的问题。MVP中展现交互逻辑完全由Presenter负责,并通过View接口与View通信。
但是MVP也存在一些问题。展现逻辑的复用粒度由View接口的力度决定,而且,当展现逻辑非常复杂,就会造成Presenter与View联系过于紧密,限制了复用能力。
2.MVP VS MVVM
相对于MVP,MVVM中展现逻辑的复用更为彻底。MVVM 中创新的提出了抽象View的概念 ViewModel,ViewModel封装了View的一切状态和行为,但与具体的显示框架,布局规则没有任何关系。
这就使得ViewModel可以满足几乎任何场景下的被复用需求。基于传统的MVVM概念和google 推出的AAC 架构组件,我们开发了一套更符合自己实际情况的MVVM方案。
下面开始详细的介绍我们的MVVM 实践。
3.MVVM 中的依赖原则
MVVM遵循单向依赖原则,依赖关系从上向下依次为 View 依赖 ViewModel,ViewModel依赖 Model,不允许跨层依赖。这样的好处是可以使调用依赖关系更加清晰。
沿着依赖方向的通信方式以直接方法调用为主。由于不能违背依赖原则,从下向上的通信主要借助观察者模式实现,上层注册观察者,下层需要通信时,触发观察者回调。
4.MVVM 中的类层次
如下图,MVVM 中View ViewModel Model 都有自己的类层次结构。
其中,View 需要承载布局渲染等逻辑,所以Activity, Fragment,ViewHolder 及其子类属于View的角色范畴。
ViewModel作为View的抽象表示,分别针对页面和列表item提供了不同的子类实现。
Model中BaseModel类主要封装了网络库相关的方法调用,具体子类可以根据不同场景,实现不同的需求。
5.MVVM 在首页的实践
首页算是得到app中比较特殊的页面。最外层结构是一个列表,列表中每个item 独立请求需要显示的业务数据。
我们在使用mvvm架构整个页面的过程中,确实遇到了一些问题。这些问题,大概包含了三个方面的内容。
问题1:如何复用逻辑
面向对象开发中,复用的主要手段包括组合还有继承。那么,mvvm中,展现逻辑和数据逻辑的复用,也不外乎这两种手段。
例如,得到app 首页中 推荐课程,推荐听书都包含负反馈和底部推荐标签功能,我们将这两个功能抽象到TagsItemVM 中,课程,听书VM分别继承TagsItemVM,这样就可以非常容易的实现这两个展现交互逻辑的复用。
问题2:ViewModel如何感知View的生命周期变化
在mvvm中,View直接持有ViewModel的引用,所以,当View的生命周期发生变化,ViewModel对应的生命周期函数会立即被调用。通过这种方式,我们确保ViewModel与View的生命周期能够保持同步
但由于页面Activity,Fragment和列表ItemViewHolder具有不同的生命周期形式,所以他们对应的ViewModel会有不同的生命周期回调。
ViewModel内部使用一个对象维护自身的生命周期状态,当ViewModel与View绑定后,ViewModel的生命周期活跃,当ViewModel与View解除绑定后,ViewModel的生命周期不活跃。
此外,ViewModel生命周期的活跃状态受其parent ViewModel的生命周期影响,当parent ViewModel 不活跃,当前ViewModel的生命周期同样已经不活跃。
通过感知ViewModel生命周期的活跃状态,在生命周期不活跃时,执行某些资源的清理操作,可以有效防止内存泄露。
code block
问题3:ViewModel之间如何互相通信
ViewModel之间通信主要依赖于LifecycleBus,这是一种特殊的事件总线。
ViewModel不活跃时,由于会断开与总线的链接,所以不会收到总线上的事件。
这样的设计主要考虑到 viewmodel 已经不在与View有绑定关系,ViewModel继续关注View中的事件通知是没有意义的,还可能带来其他未知的问题。
这种方案还带来了另外的好处,使event的派发效率更好,因为事件只会派发到活跃的ViewModel
6.消除模板代码,简化开发
如上图,传统的MVVM实现中,如果我们希望实现一个列表效果,至少需要新创建四个文件,view adapter,item view hodler,item view model,layout file。但是,view adapter和view holder中主要是一些模板代码,几乎没有有效的业务逻辑。
所以,我们为了解决这个问题,在MVVM framework中提供三个基础设施类,通用的view adapter,通用的view holder,bindItemVH注解。
这样,我们再实现同样的列表效果,只需要创建两个文件 item view model和layout file。
然后使用注解关联这两个文件。运行时,通用的view adapter 根据注解指定的关联关系,就可以将相关的ui渲染到屏幕上。
7.我们的收获
目前我们已经上线首页,已购的mvvm改造,消息中心,问答,搜索,课程的mvvm方案也已经完成。
通过mvvm开发架构的升级,我们的程序结构更加清晰,代码可读性更高,通过运行时注解的支持,彻底消除了不必要的模板代码,使我们的开发更加顺畅。
三、未来规划
未来,我们想尝试的方向有组件平台化,插件化,跨平台,希望通过这些手段,进一步提升团队协作效能,提高app研发效率,和用户体验。
作者:刘硕,得到安卓客户端。主要负责业务架构方向的工程效能提升相关工作。我们希望,通过对工程架构的改造升级,践行工程化方面的一些通用实践。使安卓团队在研发效率和研发体验上得到整体提升,提高app稳定性。
相关推荐
- 搭建一个20人的办公网络(适用于20多人的小型办公网络环境)
-
楼主有5台机上网,则需要一个8口路由器,组网方法如下:设备:1、8口路由器一台,其中8口为LAN(局域网)端口,一个WAN(广域网)端口,价格100--400元2、网线N米,这个你自己会看了:)...
- 笔记本电脑各种参数介绍(笔记本电脑各项参数新手普及知识)
-
1、CPU:这个主要取决于频率和二级缓存,频率越高、二级缓存越大,速度越快,现在的CPU有三级缓存、四级缓存等,都影响相应速度。2、内存:内存的存取速度取决于接口、颗粒数量多少与储存大小,一般来说,内...
- 汉字上面带拼音输入法下载(字上面带拼音的输入法是哪个)
-
使用手机上的拼音输入法打成汉字的方法如下:1.打开手机上的拼音输入法,在输入框中输入汉字的拼音,例如“nihao”。2.根据输入法提示的候选词,选择正确的汉字。例如,如果输入“nihao”,输...
- xpsp3安装版系统下载(windowsxpsp3安装教程)
-
xpsp3纯净版在采用微软封装部署技术的基础上,结合作者的实际工作经验,融合了许多实用的功能。它通过一键分区、一键装系统、自动装驱动、一键设定分辨率,一键填IP,一键Ghost备份(恢复)等一系列...
- 没有备份的手机数据怎么恢复
-
手机没有备份恢复数据方法如下1、使用数据线将手机与电脑连接好,在“我的电脑”中可以看到手机的盘符。 2、将手机开启USB调试模式。在手机设置中找到开发者选项,然后点击“开启USB调试模式”。 3、...
- 电脑怎么激活windows11专业版
-
win11专业版激活方法有多种,以下提供两种常用的激活方式:方法一:使用激活密钥激活。在win11桌面上右键点击“此电脑”,选择“属性”选项。进入属性页面后,点击“更改产品密钥或升级windows”。...
- 华为手机助手下载官网(华为手机助手app下载专区)
-
华为手机助手策略调整,已不支持从应用市场下载手机助手,目前华为手机助手是需要在电脑上下载或更新手机助手到最新版本,https://consumer.huawei.com/cn/support/his...
- 光纤线断了怎么接(宽带光纤线断了怎么接)
-
宽带光纤线断了可以重接,具体操作方法如下:1、光纤连接的时候要根据束管内,同色相连,同芯相连,按顺序进行连接,由大到小。一般有三种连接方法,分别是熔接、活动连接和机械连接。2、连接的时候要开剥光缆,抛...
- win7旗舰版和专业版区别(win7旗舰版跟专业版)
-
1、功能区别:Win7旗舰版比专业版多了三个功能,分别是Bitlocker、BitlockerToGo和多语言界面; 2、用途区别:旗舰版的功能是所有版本中最全最强大的,占用的系统资源,...
- 万能连接钥匙(万能wifi连接钥匙下载)
-
1、首先打开wifi万能钥匙软件,若手机没有开启WLAN,就根据软件提示打开WLAN开关;2、打开WLAN开关后,会显示附近的WiFi,如果知道密码,可点击相应WiFi后点击‘输入密码’连接;3、若不...
- 雨林木风音乐叫什么(雨林木风是啥)
-
雨林木风的创始人是陈年鑫先生。陈年鑫先生于1999年创立了雨林木风公司,其初衷是为满足中国市场对高品质、高性能电脑的需求。在陈年鑫先生的领导下,雨林木风以技术创新、产品质量和客户服务为核心价值,不断推...
- aics6序列号永久序列号(aics6破解序列号)
-
关于AICS6这个版本,虽然是比较久远的版本,但是在功能上也是十分全面和强大的,作为一名平面设计师的话,AICS6的现有的功能已经能够应付几乎所有的设计工作了……到底AICC2019的功能是不是...
- 手机可以装电脑系统吗(手机可以装电脑系统吗怎么装)
-
答题公式1:手机可以通过数据线或无线连接的方式给电脑装系统。手机安装系统需要一定的技巧和软件支持,一般需要通过数据线或无线连接的方式与电脑连接,并下载相应的软件和系统文件进行安装。对于大部分手机用户来...
- 一周热门
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
