同步吐槽在知乎:https://www.zhihu.com/question/317769041/answer/1961442803629393838
每次开发安卓原生app,都忍不住上网搜索:安卓开发为什么这么难
简直就是低效的代名词,以前只是ui写起来麻烦,现在ui写起来简单了,但是整个系统的复杂度令人难以忍受。想要做安卓开发,不仅要懂业务逻辑,还要成为半个 Gradle 专家、半个系统适配专家和半个架构师,外加还要忍受垃圾的就业市场。实在不行咱们还是抄一抄前端框架吧,虽然经常有人吐槽前端天天造轮子,但是好歹人家从ide插件、包管理器、工具链到开发都是越来越好用,我实在看不出来安卓开发哪里有进步
1. 几乎毫无进步的工具链
android studio和gradle更新了5年,几乎没有任何实用的功能变化,而且密码的这俩还是出了名的内存和 CPU 消耗大户,电脑风扇狂转是家常便饭,慢的一批的同时还特别难用。Gradle版本需要和agp、ide版本对应才能正常编译成功,版本范围还得去官网摸,这是人能想出来的设计吗?几乎99%从github拉下来的开源安卓项目都无法正常编译。
2. 技术栈混乱,新人根本不知道怎么入门
一个小小的安卓开发,语言层面kotlin、java并行,UI层面xml、compose、flutter并行,sdk层面support库和jetpack并行,外加狗屎的gradle,直接把大多数入门的小白拍在岸上。
3. 设计模式是谷歌工程师的KPI吗?
官方天天就鼓捣那破b设计模式,“最佳实践”最多不超过2年就变老黄历,光我用过的就有MVC、MVP、MVVM 和 MVI,而且设计模式的“最佳实践”也在不断变化:早期的 Android MVVM每个UI状态都用 ObservableField,后来又用 LiveData,谷歌现在推荐的最佳实践又变成了:用一个不可变的 UI 状态,通过 StateFlow 来管理,我内心真的是一万个草尼玛奔腾
4. 无处不在的Context
干什么都要传Context,能不能学学ios把你那context解耦了?安卓每次传context都像在做题:
- 在
Activity
里,用this
还是getApplicationContext()
? - 在
Fragment
里,用getContext()
还是requireContext()
还是getActivity()
? - 构造子
View
,用getContext()
? - 给工具类传入一个
Context
试试… 布豪,内存泄露了
试想一下,你能忍受js变成这样吗:window
对象有好几个版本。一个是‘全局版’,一个是‘页面版’,还有一个是‘组件版’。每次调用一个API前,都必须先决定是传入 window
对象还是一个代表当前 <div>
的特殊对象,选错了就会导致内存泄漏或页面崩溃
5. Activity/Fragment 销毁重建机制
- 应用切了一下后台,Activity被销毁了;
- 旋转一下屏幕,Activity又被销毁了;
- 到晚上了手机自动切换到夜间主题,Activity又双叒叕被销毁了;
密码的用户的应用还在前台呢你就销毁!你销毁了,为什么要我来恢复状态???这种非功能性的开发复杂度,与业务逻辑无关,纯粹由平台和生态引起。大量的、本应由框架透明处理的复杂性,直接暴露给了应用层开发者,迫使开发者花费巨量精力去进行防御性编程
6. 状态管理越来越复杂
从mvvm开始状态管理越来越复杂:ViewModel、LiveData、StateFlow、SharedFlow、生命周期、冷热流、背压…… 对于 MVI 架构,还需要引入Event、State、Side Effect等一整套概念,即使是一个简单的操作,样板代码也非常多,心智负担越来越高,代码质量全看开发者水平。
7. 迷之编译时间和编译错误
Google 推出了各种优化手段,理论上,增量编译应该很快,但实际上,稍微修改一下常量、资源文件、或者某个模块的公共 API,就可能导致大范围的重新编译。WTF?你永远不知道下一次按下“Run”按钮是 10 秒还是 10 分钟。activity热更新和Jetpack Compose 的Preview功能偶尔会无故失败或加载极慢,完全不告诉你为啥,白白浪费时间
8. 页面导航和栈管理一团乱麻
虽然现在有了Jetpack Navigation Component,但是旧项目有机会迁移吗?开发者需要手动管理FragmentTransaction、处理各种launchMode、Intent Flag,极其容易出错。获取navhost、navcontroller,不利用依赖注入的情况下也很麻烦,完全没有前端框架的useRoute方便
9. SDK混乱\API不可靠
打个比方,实现一个后台任务,有WorkManager、Foreground Service、AlarmManager、Boardcast N种选择方式;
实现通知,有渠道推送和本地推送。
然而当你都用了一遍后,发现原来后台任务和通知是否能按预期运行还是得看操作系统的脸色。开发者几乎无法通过代码解决,唯一的办法是写长长的“操作指南”,引导用户去手机的各种深层设置里(如电池优化、自启动管理、应用锁等)把自己的 App 加入“白名单”。
这种体验对用户和开发者都是一场灾难,开发者和厂商被迫研究各种“黑科技”,最终形成了“后台保活”这个畸形的子领域,与Google的政策背道而驰。
10. 无尽的 API 废弃与迁移成本
虽然 Google 努力在推新版本,但市场上 Android 8、9、10、11、12、13、14 、15同时存在,且占有率都不低,很多曾经被官方大力推广的 API 和库,短时间内就被废弃。一个新 API,你不仅要用,还要为数亿无法升级的用户写兼容性代码,代码中充斥大量的 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.XXX)
,丑陋程度堪比go的 if err != nil
。
国内厂商定制(魔改)地狱是比系统版本碎片化更恐怖的存在,同一个标准 Android API,在不同厂商的 ROM 上可能有截然不同的行为,你不仅要适配 Android 版本,还要适配 MIUI 版本、EMUI 版本。
11. 测试工程师都没办法愉快摸鱼
ui测试编写起来繁琐、运行起来极慢且极其不稳定,测试经常因为各种奇怪的原因(动画、网络延迟、模拟器状态)失败,维护成本非常高。一旦涉及到需要 Android Framework 的集成测试或 UI 测试,就必须依赖模拟器或真机,完全没有办法在 CI/CD 环境中高效、稳定地运行测试
12.依赖注入几乎变成标配
由于谷歌的垃圾设计,导致开发过程中很多场景不得不使用依赖注入,注解、组件、作用域,对于新人开发直接一脸懵逼。