Google Android 官方架构示例,我在起跑线等你
每每发行架构组件,亦不忘反向输出英文文档,供老外阅读交流。
就框架而言,在国外易获青睐认可,反观国内某些论坛,则易招黑。
其人阴阳怪气、逼逼赖赖,假借洋人文章官方示例踢馆拉踩,以莫须有之罪名孤立抹黑、杀人诛心,而我恰恰一向对官方示例抱以质疑,
故今日不如把话摊开讲,对冲牛鬼蛇神之狐假虎威。
官方示例一宗罪之 “违背原则之原则”
据 wiki 百科介绍,“最佳实践” 乃管理学概念,意即 “认为存在某种技术、方法、过程、活动或机制可使生产或管理实践的结果达到最优,并减少出错的可能性”,
故易知,架构模式即乃 “软件工程” 领域 “最佳实践”。
软件工程最佳实践有其原则,即 “设计模式 6 大原则”。然如说哪个原则是 6 原则之首、宁违背其他原则,亦不可违背此原则 —— 此即 “单一职责原则”。
单一职责原则与 “本质” 直接挂钩,架构模式设计如违背单一职责原则,是后续所有弊病祸根所在。如这么说无体会,那就继续往下,一睹为快~
官方示例二宗罪之 “ViewModel 职责混杂”
Jetpack ViewModel 本质有二,
一是页面状态容器,使页面旋屏重建后可直接从 ViewModel 拿取数据,免去传统 onSaveInstanceState、onRestoreInstanceState 之苦,
二是生命周期作用域可设定之容器,例如作用域设定为 Activity 级,则 Activity 旗下 Fragments 皆可共享 Activity 级 ViewModel 之公共数据。
由此易得,该框架违背单一职责原则。
但其实,这俩功能都有存在意义。那怎办,此时最佳实践即,通过创建子类,继续划分职责,直至各司其职即可,
例如可将 ViewModel 划分为 State-Holder 和 Event-Handler,
前者专职托管页面状态数据,是表现层组件,可作为静态内部类声明于 Activity/Fragment 中,作用域仅限该页面本身,为该页面专属;
后者专职业务逻辑处理及结果统一分发,是领域层组件,可为多个 Activity/Fragment 复用。如作为数据请求者(Requester),作用域可限定为页面本身;如作为跨页面通信者(PageMessenger),作用域可设定为 Activity(单 Activity 架构而言)或 Application。
也因此,State-Holder 为 State 唯一可信源,Event-Handler 为 Event 唯一可信源,数据之来去流程,总是从页面发起事件,交由 Event-Handler 处理并回传结果至页面。在回传之回调中,首先应将数据赋予给 State-Holder 之 States,然后再通知页面控件根据 State-Holder 之 States 完成渲染,
由此,当页面旋屏重建时,控件仍是以 State-Holder 作为唯一可信源,拿取最后一次 States 进行渲染,而 Event-Handler 在完成一次性推送后,不必自作多情自动回推,以免好心办坏事。
—— 正常流程就该是这样。
官方示例三宗罪之 “LiveData 粘性设计”
LiveData 之所以会被设计为粘性,正是一宗罪乃至二宗罪所致,
—— 因官方示例中,ViewModel 既扮演 State-Holder,又扮演 Event-Handler,使得 LiveData 既扮演 States,又扮演 Event。也即官方示例认为,LiveData 是页面数据唯一来源,页面控件仅能从 LiveData 这一处获取数据完成渲染,故 LiveData 只可设计为粘性,于观察者注册时,自动回推最后一次数据。
而这蹩脚设计,恰恰又于跨页面通信场景自相矛盾。官方对此态度是,假装无事。5 年已过去,其文档仍在避重就轻提供 “实则现实中易误用乃至出错”之示例,而 SingleLiveEvent 等实验性半成品框架,完全无法用于生产环境,
故便有后来,国人集思广益,祭出 UnPeek-LiveData[1]。
官方示例四宗罪之 “生搬硬套”
对,此非初学者生搬硬套,而是官方自身。Jetpack 架构组件乃借鉴前端 Redux 框架 “单向数据流” 思想。
都说学技术要学本质,单向数据流仅是一形式,非本质,或者说,单向数据流是解决某类问题最佳实践,非这类问题本质。
故我们须找到问题背后本质,如此即便不使用 “单向数据流”,亦可 “正确解决问题”。反之,生搬硬套 “单向数据流”,未必全然正确,否则也就不会有 LiveData 蹩脚设计。
“KunMinX,求求你不要再说了,会被 Google 爸爸封 … sha de”
官方示例五宗罪之 “撒手不管”
既然 LiveData 之蹩脚设计覆水难收,那就干脆 … 哼哼哼,祭出 Kotlin Flow,诱使各路人士以 “不支持消息连发” 为由跟风抹杀 LiveData,不着痕迹使之淡出人视线。
然 Kotlin Flow 仅适用于 Kotlin,非 Java 项目可及。且现实情况是,多数公司 “远古巨型项目” 皆需 Java 维护升级,而 Java 恰是一致性问题大户,亟需架构组件助力消除隐患。
故开发者 Kotlin 你到底是学还是不学?给我学!~
“KunMinX,你够了,话不能乱说,LiveData 确实不支持消息连发,MVI 场景不够用。不过,唯一可信源成熟态 MVI-Dispatcher[2] 我倒要试试,如此 LiveData「消除 mutable 样板代码 + 支持事件连发 + 杜绝 setValue 误用」之事还能苟一苟”
官方示例六宗罪之 “更迭迟缓”
此宗罪皆乃一二三宗罪蒙蔽所致。职责混杂之 ViewModel,使其架构模式看似 “三层”,实则 2.5 层,ViewModel 既属表现层,又属领域层,
好在其经过 4 年摸索,于 2021 年底正式引入 domain,确立 ui、domain、data 三层。虽吾等这天已 3 年之久,然仍未见其从根本上拆解 ViewModel 等框架之职责,此乃原罪。
“KunMinX,我就是看不惯你,我只许洋人磨洋工放臭屁,不许你公开发表经生产环境检验之见解。你实事求是摆事实讲道理在我眼里才是放屁,我就是要有一说一/说实话/讲公道话/拉拢帮凶评评理/唾沫星子淹死你 … ”
官方示例七宗 …
… 别什么罪不罪的,其实吾甚无语给人事物定罪,显得自己高高在上似审判官。
到此为止,该说已说。
天下本就无完美事物,有则是创作者不断死磕,精益求精。
感谢官方为开发者带来优秀框架,Lifecycle,LiveData,ViewModel,DataBinding,Navigation 等,吾皆深知其义,亦改造开源去其糟粕,愿精华永世流传。
参考资料
UnPeek-LiveData: https://github.com/KunMinX/UnPeek-LiveData
[2]唯一可信源成熟态 MVI-Dispatcher: https://github.com/KunMinX/MVI-Dispatcher