作者:烧麦

地址: https://Zhan LAN.zhi Hu.com/p/51308091
下蛋的同学们,星期一早上好! 祝大家新的一周精神饱满! 今天欢迎杭州的烧麦先生给大家展示安卓体系结构模型的晾衣架!
前言
升学e网通是杭州铭师堂旗下的在线教育产品,集助学、补习、升学为一体,是国内领先的高中生综合辅导系统,为高中同学提供视频学习、补习备考、志愿者志愿、升学考试等服务的平台在客户端的高速业务迭代下,我们升级了安卓客户端的体系结构。 使用这篇文章来分享我们最近几个月的技术工作。
我们年轻时采用了大多数客户端都采用的MVP体系结构。 但是,随着业务代码的增加,我们遇到了以下令人头疼的问题。
生命周期失去控制
在我们的初始MVP的架构中,view层是Actiivity、Fragment等的托管视图的部分,该部分一般有自己的生命周期,view层对象中有Presenter的对象实例但是,无法确保presenter层中对象的生命周期和view层的一致性。 例如,团队的同学很早就在v层的destroy上写了以下代码。
@ overridepublicvoidondestroy { this=; }此处暂时不讨论这种方法是否必要或正确,但在view层对象清空后,可能会发生从presenter层到view层的调用,从而导致意外错误
例如,在presenter层中添加了最经典的Retrofit Rxjava代码。 如果网很弱,则不会返回网络请求,而是回滚接口。 当丢弃当前Activity对象、完成presenter中的网络回调并调用view层的方法刷新UI时,将出现crash (点扩展)。
因此,每次请求网络时,我们都需要向Rxjava的Flowable对象添加订阅,并在v层对象的生命周期中调用取消订阅。
大致的代码如下
add subscribe ( my API.request network ) requestmodel ).compose.subscribewith ) newmysubscriber ) @ overridepublicvoidonfaice 如果团队成员增加,新同学入职时不强调此规则,则容易出现线路点扩展异常。
基础对象的维护很难
在mvp中,抽象了BasePresenterActivity和BaseActivity等基类。 此代码可能类似于以下内容:
publicabstractclassbasepresenteractivityextendsactivity { @ overridepublicvoidoncreate ( bundlesavedinstancestate ) super .={//todosomething } this.setcontentview ( get layout ); //todosomething}oncreate具有许多代码逻辑。 多次迭代开发和新技术的进化可能需要其他类似功能的Activity。 或者,某些Fragment可能需要类似的逻辑。 您还可以重建这部分的代码,但是新学生可能只关心我需要复制的Activity相关逻辑,或者只关心生命周期相关逻辑。 在这种情况下,Activity和生命周期逻辑会结合在一起,结果很难维护。
新同学抱着“不知道把长代码直接移动到外面会不会出错”的想法,放弃重构的可能性很高。 结果,新逻辑和旧逻辑都结合到基类中,基类越来越少有人维护,也不敢工作了。
MVP接口过多,影响可维护性
使用MVP的最初目的是解除代码的分层,使其更容易读取和维护。 但是,随着代码量的增加,view层和presenter层通过接口进行交互,接口定义的方法也越来越多。 修改单个逻辑可能需要查找并修改受影响的方法。
整理MVP的数据流,可以看到MVP其实是一个双向的数据流。 视图可以将数据传递到presenter,而presenter可以将数据传递到视图。 逻辑变得复杂之后极其不便。
团队同学对MVP的理解不一致
MVP虽然基本原理简单,但只是MVC的一个改进和变种。 但是,网络上其实也有很多MVP的写法。 团队中对于是否应该保证presenter层只有纯的Java/Kotlin码,不会出现Android的相关包,也有各自的意见。
综合以上MVP架构面临的问题,升级新的架构集,业务代码抽象度高,开发简单,代码易维护,显得十分迫切。 于是我们开始关注谷歌官方给出的Jetpack架构组件。
Jetpack
Android Jetpack根据谷歌在今年的IO大会上、去年IO大会上发布的Android Architecture Component进一步发布的内容来看,对于我们的问题,我们关注的主要是架构组件
生命周期
使用Lifecycle重建了基本的Activity类,将与Lifecycle相关的内容和具体逻辑进行了分类。
abstractclassbaseactivity:appcompatactivity { overridefunoncreate ( savedinstancestate:bundle ) super.oncreate } savedincty ew(bindlayout ) life cycle.add observer ( baseactivitylifecycle ) }/*** Activity的layoutquestionid**
classbaseactivitylifecycle ( val context:context ) ) life cycle observer { privatevalvalue:string=@ onlifecyclevent ) life @ onlifecycleevent ( life cycle.event.on _ start ) fun onstart {/todosomething } @ onng funonresume (/todosomething ) ) onlifecycleevent ) ) lifecycle.event.on_destroy ) funondestroy )//todosomething基类的Activity表示每个生命周期如果某个同学需要重构BaseFragment类,则可以直接复用此lifecycle的代码,不用担心自己遗漏了什么lifecycle相关的初始化。
视图模型
使用ViewModel解决自制MVP架构中的presenter生命周期问题。
这里的ViewModel和MVVM的ViewModel不是一回事。 简单来说,实际上ViewModel仍然是Presenter。 当然,它是自动管理员生命周期的Presenter。 ViewModel的官方网站概要如下。
您可以从manage ui-relateddatainalifecycle-conscious way文档中查看ViewModel的基本用法。
从官方网站的这张图中可以看到,ViewModel将与view对象的onDestory一起执行onCleared方法销毁。
您可以将数据逻辑保存在ViewModel中,以便在Activity生命周期发生变化时从ViewModel中检索数据并恢复用户界面。 在ViewMdoel中,它还负责简单的逻辑操作。
文档中记载的ViewModel的初始化方法如下。
在开发ViewModelproviders.of(this ).get ) modelclass:class.Java的过程中,我们始终需要将从以前的Activity发送来的数据传递给viewmodel 此时,我们可以使用viewmodelprodel,工厂进行初始化。
团队内的约定是,为了更复杂的逻辑抽象,不限制Activity和ViewModel的对应关系。 一个Activity可以有多个ViewModel对象。 但是,对于许多逻辑上不太复杂的页面,仍然需要一个Activity一个ViewModel就足够了,因此还编写了相应的基类:
其中:
arguments传递给ViewModel的参数包含在Bundle对象中。 使用这个班的同学只关心他要传达什么,而不需要在意Factory的用法。
viewModelClass返回ViewModel的Class对象
ViewModel的初始化如下图所示。
需要注意的是,使用Factory初始化对象时,proguard-rules.pro将消除相关类的混淆,因为它使用了反射。
如果你自己使用,你需要添加:
- keepclassmemberspublicclass * extends Android.arch.life cycle.viewmodel { public ( )例如,如果我们封装在上面,就需要添加。
- keepclassmemberspublicclass * extends.base ViewModel { public ( . ) }解决了生命周期问题,因此我们在viewmodel中获取了逻辑处理的结果,如何进行我们选择了用LiveData来完成这些。
LiveData是可观察数据的所有者,具有生命周期的感觉。 简单的LiveData的使用方法如下。
在ViewModel中为LiveData指定值:
myLiveData.post(value )在view中观察livedata。
有关更多地使用mview model.my live data.observer { v-v.let { update ui ( it ) } livedata的信息,将在下一章中介绍。
拥有View、ViewModel和LiveData后,我们整理了数据流
这里可以看到,数据的传输方向其实是单向的数据流。 从UI层到逻辑层的数据不会互相扔。 即使代码变多了,只要关注单方面的数据变化就可以很容易地知道逻辑。 代码也变得容易维护。
通过类比,您会发现该体系结构与前端React Redux的Flux体系结构非常相似。
实际上,在Jetpack的源代码中也可以看到Store和Dispatcher这样的概念。 虽然业务代码的结构还和MVP没有很大的不同,但是从整体的角度来看,我们的体系结构就像Flux一样。
在这里,我们在自制MVP的过程中,很容易解决了令人头疼的生命周期问题。 也不用担心数据返回时View会被丢弃。 因为此时LiveData不再执行观察器回调。
使用页面
在Jetpack中,另一个引人注目的组件是Paging。 最新一代的图像选择组件还使用Paging作为列表分页加载的载体。
Paging将专辑选择的逻辑抽象为几个部分:
数据
PagedList是继承了AbstractList的List的子类,它包含数据源检索到的数据。
DataSource数据源的概念分别提供PageKeyedDataSource、ItemKeyedDataSource和PositionalDataSource,数据源可以定义自己的数据加载逻辑
用户界面
UI部分的页面提供了一个新的页面适配器,在实例化这个适配器时,我们需要提供自己实现的DiffUtil.ItemCallback或者AsyncDifferConfig。
选择影集时,会将一定量的图像导入到每页中,以避免一次加载可能显示所有本地图像的纸箱。
与配置对应的配置:
到此为止,我们实现了优雅的列表寻呼加载。 可以绘制Paging的简单体系结构图:
一般来说,在我们最原始的方法中,有列表UI的部分需要知道数据的出处等逻辑部分。 Paging实际上是将列表的寻呼加载这一动作抽象化的Presenter层及其下游处理。 在这个模型中,业务的作者可以模板化UI部分的代码,只关心业务逻辑。 另外,可以将业务逻辑中的数据获取写入DataSource,进一步解除寻呼加载的操作。
总结
通过实践,总结了Android Jetpack组件的几个优点。
官方产品值得第一时间使用,可以保证稳定性。
通过自建MVP体系结构,解决了由于生命周期难以控制、接口复杂等原因导致的部分代码难以维护的问题。
架构清晰,不会因为理解不同而写风格不同的代码。
同时,我们也有一些自己的想法,考虑如何更好地升级架构。 我们有必要整理出现的体系结构不足。 升级新体系结构终究是为了解决问题,而不是为了追求新技术而升级体系结构。 体系结构升级的过程应尽量减少对现有体系结构的入侵性。 如果可以进行未被识别的置换,就更好了。 有些细节可以封装起来,让其他业务线的同学只关注业务的处理流程。
我们已经讨论了进入Enternet的客户端的体系结构升级,以及Android Jetpack在团队中的实践。 目前,本文介绍的部分全部在线,部分内容已经过一些版本的迭代,没有出现明显的在线crash。
远景
首次进行体系结构升级后,在客户端稳定性的前提下,团队将进一步尝试进行体系结构升级。 这包括以下内容:
DI部署:体系结构在逐步完善的过程中,分为数据库、网络、复杂逻辑处理层等多个代码层。 这些对象现在在我们的代码中是单实例类。 单个示例同时意味着生命周期难以管理,需要依赖注入库来管理对象。 现在,我们正在对kotlin的koin进行尝试。
尝试其他Jetpack体系结构组件: Navigation、WorkManager等。
进一步使用paging:paging目前尚未在我们的客户端上大量使用。 以后,它将尝试与现有的三方RecyclerView组件组合,在网络请求场景中创建寻呼加载逻辑。
最近的文章:
要从私人程序员成长为高级程序员,据说年薪50万的程序员在周末做这件事高效地开发小程序。 mpvue理解今天的问题。
你现在用的是什么模式? 你喜欢Android的新恋人AAC吗?
消息格式:
工时记录卡x天,a:XXX。
参加打卡活动:
光遇1.23每日任务该怎么完成呢?在光遇世界有着各种精彩有趣的任务内容,玩家可以完成后获取大量的游戏奖励,小编
《云顶之弈》这游戏中卢安娜的飓风这件武器最近版本更新中被强化了,分裂攻击的伤害效果大大提升。有些小伙伴
迷你世界激活码2023是哪些呢?在精彩有趣的全新挑战活动中,玩家可以体验到更多丰富的游戏奖励。小编今天准备了
很多传奇的老玩家关心关于贪玩蓝月祝福油怎么用的相关问题,今天柠檬友玩小编给大家搜集整理了如下内容,希望对
《魔兽世界怀旧服》中存在着多样的公会制度,DKPROLL团就是其中之一,关于这个制度的意思好优劣势,本文将为你解
斗罗大陆魂师对决阵容最佳搭配2023,新版本上线了很多魂师,我们应该如何搭配呢?以下为大家分享新版本顶级阵容大
时间:2022-11-15
时间:2022-11-15
时间:2022-11-15
时间:2022-11-15
时间:2022-11-15
时间:2022-11-15
时间:2022-11-15
时间:2022-11-15
时间:2022-11-15
时间:2022-11-15