当你好不容易学会了某个框架或者工具,觉得它很好用的时候,它或许就要过时了。
![76eeb5c5108ba39c3086c0c6de8ff9ab.png](https://i-blog.csdnimg.cn/blog_migrate/3fb8cf512743fc813e90a3dcf48a6b8f.jpeg)
作者 | Vasiliy Zukanov,已获翻译授权
译者 | 罗昭成,Android 开发者;责编 | 唐小引
封图 | CSDN 付费下载自东方 IC
出品 | CSDN(ID:CSDNnews)
许多 Android 开发者经常会问我,要学会哪些东西才能成为一个优秀的 Android 工程师?对于这个问题,他们的描述或多或少都有些差异。但是,总体来说,我们都需要学习一系列的技能,才能成为一个优秀的 Android 工程师。
Android 原生开发的生态系统变化得非常快。至少在过去的五年时间里,我经历过很多 Android 的变化,并且花费大量的时间参与其中。这几年里,Google 每两到三年,就会推出一组新的库和框架作为官方 Android 原生开发的指导方针。我花了大量的时间,回顾了这几年的变化,希望从中找出好坏。我相信,有很多的 Android 开发者,也和我一样。
过去的一年,大量的内容被添加、被废弃或被删除,文档被更改,新的官方指导方针被引入等等。即使我以 Android 原生开发生态系统的的标准来看待这些问题,所发生的这些事情,都是非常疯狂的。当我开始思考这些内容的时候,我已经无法在我的脑海中描绘出一个完整的、详细的 Android 开发环境。
因此,我决定要花一些时间去整理这些内容,然后再来写这篇文章。本文中,我会试图去总结 Android 原生开发的生态系统中发的事情,并且对原生开发未来的走向做一些预测。我会将我的想法分成不同的章节去叙述,这些内容没有特定的顺序,但我会把最有争议的内容放在文章最后。
我希望我的这篇文章可以给你带来一些启发和帮助,但是你需要记住,本文不可能包含所有的内容,有可能会漏掉许多重要的观点,并且本文中的内容可能会包含我个人的一些偏见。
![232811dcb321435de7623ac4b3d040de.png](https://i-blog.csdnimg.cn/blog_migrate/b89e07abac0edd039f6efe87302fd287.jpeg)
AndroidX
这个事情说起来有点儿疯狂,Google 官方在一年半前就发布了 AndroidX 的预览版本。并且在一年前, AndroidX 库就已经很稳定了,与此同时,Google 官方也宣布不再对遗留的库进行支持与开发。(在我写这句话的时候,我想起我之前在 StackOverflow 上提的一个问题:为什么要将新的 API 放在 Support 库中,而不是 SDK 中?[1])
用“稳定”来描述 AndroidX 这个库有点讽刺,现在关于 AndroidX 的任何东西都是不稳定的。Google 不断地在 AndroidX 下添加新的库和框架,使用 androidx 作为命名空间。许多“老”的 API(目前还不到一年)以非常快的速度发展。
到目前为止,我已经将两个应用程序迁移到了 AndroidX 上了。一切都很顺利,我已经不记得在这个过程中,带给了我多少的“惊喜“。Google 也提供了一个工具,Jetifier 可将依赖于支持库的库迁移为依赖于等效的 AndroidX 软件包,一个非常好用的工具。然而,即使是一个很小的工程,也不能实现“一键迁移”。
我也参与了没有迁移 AndroidX 的项目(项目并不计划迁移到 AndroidX), 现在也没有任何问题,所以,不迁移 AndroidX, 在有些情况下,也是一种可行的方案。
总而言之,在新的 Android 项目中,建议直接使用 AndroidX。并且,针对老项目,我也推荐你们将迁移到 AndroidX 列到计划中,虽然现在你看不到迁移 AndroidX 过后,带来的任何收益。无论如何,你都有可能在某个时间点进行 AndroidX 的迁移,所以最好能够按照自己的进度进行迁移,而不是在 6 个月后,你需要使用某个新的 AndroidX 库时,再进行紧急迁移。
![8cf69742beee6519bf5f194df26a14f2.png](https://i-blog.csdnimg.cn/blog_migrate/3135e76c0ab0f9ff07b69657c98734a8.jpeg)
Jetpack
在讨论 AndroidX 过后,还必须要提到 Jetpack。在我的印象中,Jetpack 开始是作为“架构组件”的一把保护伞推出的。但是到后面,引入了几乎所有关于 AndroidX 的 API。因此,现在来看,我们看不到它与 AndroidX 之间的任何区别,除了 Marketing 和 PR(即市场和公关)。
当你查看 Jetpack 主页[2]时,会发现,这个页面并不是一个技术文档页面。这个更像是一个早期的 SaaS 页面。
看看例子,开发者“赞誉”:
![b3f54d89500fe235835db49efb25a578.png](https://i-blog.csdnimg.cn/blog_migrate/be363f395dab2e999f65d6ba5986c043.jpeg)
开发者赞誉
或者“信赖应用”列表:
![0f8275c4baccaf3365ca8bd080698d05.png](https://i-blog.csdnimg.cn/blog_migrate/13a54b8bbd5b8f9a7c1fdc1b722deaa2.jpeg)
信赖应用
这些在市场公关层面更受关注,如果 Jetpack 在 2020 年申请独立 IPO,我都不会感到惊讶。
不过,说真的,尝试向自己生态系统内的开发者“销售”API 的想法,我觉得存在一些问题,比如说,谁会想看搜索出来第一个就是 ViewModel 广告呢?
![e6860b369320c0f50282ad1d52365438.png](https://i-blog.csdnimg.cn/blog_migrate/01236bdadc791a401641dc215295a696.jpeg)
Android ViewModel
总而言之,Jetpack 只是 AndroidX 库的一个聚合,所以在前面写到的 AndroidX 的内容,在很大的程度上也适用于 Jetpack。在后面的内容中,我将单独讨论其中一些 API。
![25b1b3b3bc27ab6dffffd9a06a4b1a27.png](https://i-blog.csdnimg.cn/blog_migrate/97c9ad929dae4736d07dfe17d94dcb6a.jpeg)
后台作业
在 Android 应用程序不在前台执行逻辑时,你可以有很多种方式来实现后台运行,这也是 Android 动态化的用例之一。如果你不引入 doze , SyncAdapter , CGMNetworkManager , FirebaseJobDispatcher , JobScheuler 和最近的 WorkManager,可以使用常规的启动服务(非绑定服务)来实现。这些都是 Google 提供的 API , 我可以说出所有的使用方式。当然,还有一些第三方库可以使用, 例如:Android-Job。
不过,Google 最近宣布,他们将围绕 WorkManager 来统一后台任务调度[3]。这听起来非常棒,我再也不用学习那么多后台调度的知识了,只是,不知道为什么,我好像以前在哪儿听到过这句话……
我们不管将来是否会统一使用 WorkManager,WorkManager 都还存在一些问题,比如可靠性。我不想在本文中解释为什么,但是请你一定要记住,如果你想在应用程序中使用 WorkManager,实现后台作业,一定要去读一下 dontkillmyhttp://app.com 上的所有内容,并且要关注一下与 WorkManager 相关的 Google 问题列表[4]。Android 的后台作业由于碎片化等原因,导致它们一团糟,而且还很不可靠。
在过去,我一直主张尽可能对数据和其它类型的后台处理进行同步。我或许是 SyncAdapter 最后的粉丝。今天,考虑到可靠性的问题,我建议,尽可能避免后台作业。如果你的老板一直坚持要使用这个功能,请将上面的链接发给他们,告诉他们,后台作业可能会需要数百小时的工作,才能实现,并且它带来的问题也会比它带来的好处多很多。
很多情况下,后台作业的需求是不可避免的。但是在大多数情况下,你都可以不使用它。虽然有时候会给用户带来一些不便,但是这可能是到目前为止的最佳方案。
![e38f8cd8b9f3c02faa29162ff768f099.png](https://i-blog.csdnimg.cn/blog_migrate/949017f1e0e55c00f0bf15b121bfdf79.jpeg)
数据库
在有关 SQLite ORMs 的内容里面,没有什么令人吃惊的内容—— Room 主宰着一切。Room 从 2.2.0 开始,添加增量注解解析支持。不过,请你一定要记住,你应用程序的架构不应该关心你使用的是什么样的 ORM 框架。说到 Room,“架构组件”也只是一个营销术语,并不是一个技术角色。
在 Android ORM 框架中,与 Room 竞争的主要是 SQLDelight。这是一个比 Room 老很多的库。但是据我所知,在过去的一年里,它几乎被全部重写。但新版本的 SQLDelight 只针对 Kotlin。另一方面,SQLDelight 也支持 Kotlin Multiplatform,所以,随着 Kotlin 使用的增多,我预计, SQLDelight 的采用率也会随之增加。
顺便说一下,在 AndroidX 的命名空间下,也有 SQLite 的镜像。我不知道这个会有什么用处,但是如果你在应用程序中直接使用 SQLite,也可以对这个进行深入的研究。
此外,我们也不要忘记非关系型数据库,比如 Realm、Parse、Firebase、ObjectBox 等等 (其中一些,核心还是使用的 SQLite 来实现的),如果我没有记错的话,这些非关系型数据库中,大多数(甚至全部)都具有自动数据同步的功能。在之前有段时间里,它们非常地流行。但是现在,据我所知,已经不再流行了。也就是说,在短期内,我会持续关注非关系型数据库。
去年,我写了一个非常复杂的应用程序,对接了一个 Parse 的服务。这个 App 具有完全的离线支持,服务端本地化,用户指定的系统和语言设定,复杂的多媒体系统等功能。我在 Android 端上使用了 Parse 的 SDK。除了一些小的 WTF 以外,其他体验都非常棒。如果你们公司有很多后台开发人员,或者说你需要实现大量的服务端逻辑,这也许并不是最佳解决方案。但是对于仅仅只需要执行简单的 CRUD 操作的初创公司,这或许是一个不错的选择。一个警告:如果你打算采用数据库即服务解决方案(如 Firebase),请你一定要关注长期使用的成本和影响。
![b25631b55804cc6d63afd2f88fcd079e.png](https://i-blog.csdnimg.cn/blog_migrate/6761a558ac4578d103c8cdd00e5cb0b7.jpeg)
外部存储
Android 外部存储发生了一个“很有意思”的变动。
如果,你在开发 App 的时候,把 Target API 调整为 29 及以上,之前获取 SD 卡文件的方法,现在都不能使用了,并且不会提示任何异常[5]。现在,你需要使用 Android 存储访问框架来进行更细粒度的文件访问。不幸的是,Android 存储访问框架的工作原理与之前的读取方式完全不同,你可能需要对代码进行大量的重构,来实现新的文件访问和读取。
Google 原本希望在 Android 10 上,对所有的应用程序进行文件访问的限制,推广使用 Android 存储访问框架的方式进行文件访问。但是这个改动引起了社区内的强烈抗议,所以 Google 决定推迟推出这个功能。因此,现在即使你的应用程序在 Target API 29 及以上,也可以设置为在“Legacy”模式下可读取文件。不过,有可能在 Android 的下一个版本,不管你设置的 Target API 为多少,都会限制应用程序使用新的作用域访问模式。
到目前为止,我也还没有更新我应用程序的文件访问方式。但是从互联网上的讨论来看,实现新的文件访问方式是一项很具挑战的任务,虽然你的应用程序在“Legacy”模式下,没有任何异常,但是我建议你最好从现在开始,着手对代码进行重构和测试,以防发生不可控的事情。
![c4c03abf086721fc856d3a8c6a5bc58c.png](https://i-blog.csdnimg.cn/blog_migrate/9029132d0c0ea0cd4865b4f8c9778b3a.jpeg)
Shared Preferences
在几周前,AndroidX 家族增加了一个新的库,这条提交信息写道:
新的库用来替换 SharedPreferences,新库的名称还没有确定下来,这次提交只是为了评审和设计文档(请自行申请设计文档)。
现在还没有什么值得担心的。不过,从长远来看,SharedPreferences 会被废弃掉,取而代之,使用新的库来实现类似的功能。
与 SharedPreferences 不同的是,这个新的库默认情况下使用的是异步的方式[6]。换句话说,如果你需要取某个值,你需要实现回调,通过这个回调才能拿到值。
如果你对这种异步回调的原理感兴趣,你可以去看看 StackOverflow 上的这个回答[7]。Reddit 的一个用户 Tolriq 分享了他们的 App 遇到的一个 SharedPreferences 的 Bug,这个问题影响了万分之一的月活用户。对于一般的应用程序来说,这个问题并没有什么明显的影响。但在一些需要高可靠性的应用上,就显得很不可靠了。举个例子,如果在 Android 汽车上,应用程序的无响应和崩溃会引起驾驶员的注意力被分散,这将有可能导致出现交通意外。
![98856a1abac94bf478fb613836ebd4fe.png](https://i-blog.csdnimg.cn/blog_migrate/d8fd9eec8ae93b89b0fb8dea37ad54b9.jpeg)
依赖注入
在依赖注入领域,最大的新闻莫过于 Dagger-Android 被弃用,有两点需要强调一下,首先我所说的弃用,不是正式的弃用,因为官方并没有发布声明。其次,Dagger-Android 并不是指整个 Dagger 2 框架,只是指其中相对比较新的部分。详细细节可以看我的另一篇文章[8]。
在 Android 领域也存在其他的依赖注入框架,但是我不认为他们会比 Dagger 更好。值得一提的是,Koin 是一个不错的依赖注入框架,但是我依然觉得它也不会引起多大的潮流。它之所以会被采用,无非是这两个原因,一个是,它拥有比 Dagger 好很多的文档,降低了很大的学习成本。第二个是它基于 Kotlin 进行编写,因为 Kotlin 的热度,给它也带来了不少的关注。到目前为止,Kotlin 的热潮几乎已经全部过去了,所以,我预测,Koin 的关注也将会逐渐减少。
不管这些框架如何发展,手动依赖注入的发展都会很缓慢。
Google 声称:随着应用程序的增大,手动依赖注入的成本会出现指数级增长。但是我并不这么认为,我觉得 Google 既不了解 "指数" 的含义,也没有实际去“衡量”过任何东西。这个申明的内容是错误的,我希望 Google 不再使用这种方式误导社区。
事实上,这种手动依赖注入在后端比较常见(尤其是微服务中,你并不想在每个服务中都添加对注入框架的依赖),也可以正常的工作。在后端,反射被经常用到,所以后端的依赖注入框架并不需要解析编译时的代码。
在 Android 上,解决方案与后端有一些不同,我们几乎不会用反射方案的依赖注入框架,所以就只剩下 Dagger 可以用了。其实,反射虽然会影响性能,但是在大多数项目,都是可以用的。我的意思并不是建议你们使用反射方案的依赖注入框架,这个选择并非是非黑即白的,你需要按照你的要求来进行选择。
无论如何,Android 领域上, Dagger 作为依赖注入框架的现行标准,我们所有人都在使用它。尽管 Google 在宣传上,对 Dagger 的使用成本使用漂亮的绿色图形进行展示,但是 Dagger 使用成本在实际上依然会随着时间增长而快速增长。越来越多的代码,在编译构建的时候需要花费更多的时间;你的开发人员越多,代码编译的次数就越多。当然,所有的开发人员都需要学习如何使用 Dagger , 这本身就是一项很大的成本。
换句话说,虽然 Dagger 可以减少项目中编写的代码,但是需要花更多的时间去培训新人,在编译上花费更多的时候。所以,对大型项目来说,使用 Dagger 会更耗时。
在一个大型项目中,编译耗时会逐渐成为生产力的瓶颈。当然, Dagger 也提供了很多优秀新的功能来帮助你优化编译时间,但前提是,你需要知道如何使用这些工具。读到这里,我相信你对手动依赖注入会很感兴趣。
![96358477480fad14dd48f8be65aa7ffa.png](https://i-blog.csdnimg.cn/blog_migrate/bf0be9bb540c1a4a9955a5bc99d13c08.jpeg)
数据绑定
作为一个 Android 开发者,都知道在写布局的时候,会经常调用 findViewById 这个方法。DataBinding 诞生就是为了取代掉这个模板方法。老实说,在使用 findViewById 的时候,我并没有遇到过任何问题,虽然希望摆脱掉它,但我并不认为使用 DataBinding 就是一个更合理的方式。有一个好消息,很快我们就可以使用 ViewBinding 来摆脱 findViewById 了,也不需要使用 DataBinding。
说句实话,我不相信 DataBinding。对于它想解决的问题来说,这种方案在过于复杂。在使用 DataBinding 的时候,需要把代码逻辑放到 XML 布局中,这听起来很不错,但是经验丰富的开发人员都不会这么做,这个做法也是 Databinding 的另一个缺点。
早在 2016 年 11 月的时候,那个时候 Google 还在大肆宣传 DataBinding。我在 StackOverflow 的回答中作了如下预测[9]:
我可以非常自信地预测:DataBinding 不会成为行业标准。DataBinding 可以带来短期收益,但是从长远来看,它将会使代码变得不可维护。一旦 Databinding 被长期使用,它的缺点就会暴露出来,将来它一定会被废弃掉。
我没有统计过使用 DataBinding 的项目,但是很明显,它没有成为行业标准。我从来没有在自己的项目中使用过它,也很少看到其他开发者使用。据我猜测,当 ViewBinding 逐渐成熟,并且被广泛采用,DataBinding 将会作为一个“传统”框架,大量地被引用到。
![de09d051eda480bdb77916364e53a9b5.png](https://i-blog.csdnimg.cn/blog_migrate/1a5dc58102e077f337eb8a4c806d958d.jpeg)
状态保存
自从引入 ViewModel 架构组件以来,在 Android 应用程序中,当配置发生更改,保存与恢复状态的逻辑,就变成了一个烂摊子,没有人去管理。虽然这样子说有点过分,但是我觉得,这已经是我最温和的表达方式了。
Gabor Varadi(又叫 Zhuinden)在 Reddit 论坛中描述了 ViewModel 引入带来的问题[10],我不需要再去写一遍了。再次强调,不推荐使用 onRetainCustomNonConfigurationInstance,推荐使用 ViewModel。
在帖子的末尾,Gabor 作了一些预测:
![486fab706b9a4ec5cbc9f0301e112143.png](https://i-blog.csdnimg.cn/blog_migrate/a81501a14e67532e380d61129cf4b2ce.jpeg)
你知道吗?Fragment 状态保存的方法已经被弃用了[11]。
在我看来,废弃 Fragment 状态保存的方法是非常好的主意,众所周知, Fragment 的 onAttach 和 onDetach 方法就是为了支持状态保存的,现在废弃了状态保存的方法,那这两个方法也可以被废弃掉,并且这样子可以简化 Fragment 的生命周期。我长期以来都建议不保存 Fragments 的状态,忽略掉 onAttach 和 onDetach 方法,和我之前写的处理 Framgent 生命周期方法一致[12]。
尽管有很多理由表明,要废弃掉 Fragment 的状态保存,但是也不可能废弃掉 onRetainCustomNonConfigurationInstance,这个可不是我说的,是 Jake Wharton 说的。在上面 Gabor 的帖子上,他的回复获得了最多的点赞。虽然我不太赞成 Jake 所说的话,但是我找不到更好的理由去说服自己。这个方法和 ViewModel 后台使用的原理完全一致,完全没有理由废弃掉它。
那我们应该怎么对待这些废弃的方法呢?Google 不管这些方法使用的技术方案和优势,都强制所有的 Andorid 应用迁移到 ViewModel。即使这些方案有可能优于 ViewModel 本身,他们也愿意放弃。听起来有点像是阴谋论吧。
我确实不喜欢保存非配置的状态,并且废弃掉对我没有任何影响,因为我从来都没有使用过它。事实上,大多数应用程序都不需要这些方法,当然,ViewModel 也不需要。我们需要处理状态改变的方法仅仅只有 onSaveInstanceState(Bundle) 这个方法。这个方法非常简单明了,可以同时处理保存和恢复的逻辑。所以,只要能用这种方式保存状态就可以了,我相信,我不是唯一一个使用这个方法的人。虽然 Google 对 ViewModel 进行了大量的营销宣传,但是对于很多经验丰富的开发者来说, ViewModel 还是太复杂了,我们有更简单有效的方法来处理状态存储。
如果 Google 别有用心,想强制所有项目使用 ViewModel , 那么它还将废弃掉 onSaveInstanceState(Bundle)方法。这听起来有点不可思议,如果将来真的这样发展,那说明我的基础理论是正确的。
考虑到 Android 的内存管理机制,Google 不可能在没有稳定的解决方案之前就废弃掉 onSaveInstanceState(Bundle) 。“幸运的是”,我们已经可以使用 ViewModel 来完成相关工作了。
我想,在一两年内,就能看到我的理论是否正确。
总而言之,如在本节开头所说,Android 状态保存将变成一个烂摊子。两年多前,我曾经写过 ViewModel 架构组件有害的文章[13]时,我就预测 ViewModel 会对保存与恢复状态的一点点造成影响。我所预测的都变成了现实,而且现在的情况比我曾经的预测更糟。
![cccfa27c355fac8333693cdc3c4a17c7.png](https://i-blog.csdnimg.cn/blog_migrate/07291f40119dea513cfda855fac475ef.jpeg)
并发
在 Android 并发编程中,一个重要的 API 就是 AsyncTask, 不过它现在已经被弃用掉了。我之前已经写过很详细的文章分析过它了[14],在这里,将不再赘述。
下面我要说的内容,有可能会伤害很多读者,但是,请不要“恨”我。RxJava,是一个 Andorid 中常见的多线程框架。但是它现在将逐渐退出历史的舞台。从 StackOverflow 的趋势图可以看出:
![9530aceafc2e68ed6d9737db231dff4a.png](https://i-blog.csdnimg.cn/blog_migrate/ab741b9102658465ba70e6ded42a2d62.jpeg)
RxJava 使用趋势
很多开发者对这个说法提出了质疑,他们反驳说这个数据不具有代表性,并且我们可以找到其它的理由来解释图上所发生的事情。他们所说可能是正确的,我个人本身也不是数据科学家。但是从图中我们可以看到,RxJava 与 AsnycTask 有相同的斜率。如果你没有时间去学习 RxJava 如何使用,并且你的项目中也没有使用过 RxJava,我建议你不要在你的项目中使用 RxJava。事实上,我也一直不推荐使用 RxJava ,现在已经有数据支持我的这个观点了。
如果你的项目中使用了 RxJava,你也不用慌张,不需要紧急去重构你的项目。如果你的项目只有你一个人,或者整个项目组成员基本不会变动,保持项目现状就好了。但是你需要记住,以后要招具有 RxJava 开发经验的人会越来越困难,新招开发人员可能需要学习使用 RxJava。广泛使用 RxJava 的项目,在以后也会被认为"不酷",就像今天还在使用 AsyncTask 和 Loader 的项目一样。
我知道,很多 RxJava 的开发者都是 RxJava 骨灰级的粉丝,他们花了数周的时间去学习 RxJava,付出巨大的努力才说服队友在项目中使用 RxJava。现在我却在这里说 RxJava 已经过时了。我只能说,这不是我的个人意见,我只是对现有的情况进行分析,并根据我所看到的内容做出预测。我也有可能是错的。两军交战,不斩来使,请大家不要“攻击”我。
在 Kotlin 中,使用协程来实现多并发。最近使用协程实现了一些简单的用例[15],我发现它复杂、不稳定,甚至还有一些 Bug。
所有的人都在说,协程可以降低并发的复杂度,使用并发变得简单。我从来都不相信这句话,因为我知道并发从根本上来说就是很复杂的。我动手写过一些测试用例过后,据我的经验,我可以很自信的告诉你,协程不能使并变得简单。我认为,协程会增加复杂性,我建议你们谨慎使用他们。
在 Kotlin 中,协程将作为处理多线程的默认方式,如果你已经开始使用 Kotlin 进行开发,那么你应该花点时间,去学习一下,协程的使用。
据我所知,还有一个 Flow 框架,它是基于协程,添加了流运算符。在几个月之前,已经稳定了。所以现在也没啥好评价的。
![46a9041c14ed6af8c7acf39244fa11f9.png](https://i-blog.csdnimg.cn/blog_migrate/763b0f728c743e39087206db20f59f7c.jpeg)
Kotlin
现在,让我们来讨论一下 Kotlin 在 Android 领域的现状。根据我个人的经验来看,这是一个很敏感的话题,不论我所说的话有多么公正客观,都会有一些粉丝评价我所说的话是“Shit”。但从专业的角度来说,Kotlin 的话题是跳不过去的,所以,我要强调的是,这些内容只是我的个人观点,仅供参考。在 Android 开发中,使用 Kotlin,会大大地增加你的编译时间。
在我的另一篇文章中[16],我统计了使用 Kotlin 过后,编译时间的增长情况。结果是,全量编译的情况下,会增加 18%左右的耗时,如果是增量编译,则会增加 8% 左右的耗时。
Uber 和 JetBrains 联合发表了他们有关 Kotlin 对项目编译时间的影响, 在文章中,显示的结果非常的悲观。他们表示,如果你不开启 IDE 中的 annotation processors ,引入 Kotlin 的项目,编译构建的时间大约会增加四倍,如果开启了 annotation processors,编译构建的时间也会增加 50% ~ 100%。
Uber 的结果与 OkHttp 迁移到 Kotlin 后得到的结果是一致的,都是编译时长都增加了 4 倍。
别担心,虽然这个结果让人吃惊,这个也不是你的错,很多人都和你一样,正在使用 Kotlin。这个问题,虽然很重要,但是它并没有引起广泛的关注。我觉得,Google 也在试图解决这个问题。我曾问过 Google 相关的开发者,并进行了深度的交流,他们在这个问题给我的回答是:“这是一个很棘手的问题,我宁愿不做”。
Kotlin 除了会增加编译时间,直到上周,才支持增量注解处理,而 Java ,在 10 个月以前就支持了。
在两年前,我就写了篇文章用于告诫大家,过早使用 Kotlin 会存在很大的风险。你可以从评论中可以看出,我在很长的一段时间里面,都是“Kotlin 的黑粉”。
在你的实际工作中,你会发现,与上面的数据相比,Kotlin 的问题远不止于此。在大型的 Android 项目中,编译构建的时间会严重阻碍项目的发展。即使到了今天,Kotlin 已经被正式使用两年了,Kotlin 编译效率依然比 Java 差很多。不管 Kotlin 能给你带来多少优点,编译耗时的问题,都有可能导致你不在使用它。
不管如何,Google 向整个 Android 的开发生态推出 Kotlin 作为第一首选语言,现在 Kotlin 的使用量也越来越大,我们也不得不进行跟进。就我个人而言,我还没有在我的项目中使用 Kotlin。因为 Kotlin 还不够成熟,并且我的客户也不会为我的学习付费,并且我也不希望在 Kotlin 上浪费时间。但是从现在开始,Kotlin 已经逐渐稳定,我也在我拿手的项目上尝试过, 在新项目中,我也会考虑使用它进行开发。有一些开发者认为:“必须在新项目中使用 Kotlin 进行开发“,我不同意这个观点,我觉得这是一个权衡的问题,Kotlin 现在已经成为了一个重要的选项,只要适合当前的项目,就是最好的语言。
对于是否要将已有的项目迁移到 Kotlin 上, 我不能给你太好的建议。你需要根据你项目的情况,具体问题具体分析。如果你一旦决定要进行迁移,这篇文章中列举的一些可能存在的问题,可能对你有帮助。
![0f3443417e23575c893b7224d0b813b6.png](https://i-blog.csdnimg.cn/blog_migrate/e36f27801cdeab616bec6304dadced4f.jpeg)
总结
请允许我用 Android 开发者的背景,描述一下我这两年所经历的事情:
在过去的两年里,我启动了三个项目,我一直争取,至少参与其中一个项目的开发工作。我回过头来看这些已经存在的项目,并分析这些项目前期所做的技术决定对整个项目的影响。我写了这篇文章,也制作了很多 Android 开发的高级课程,也花了很多时间在互联网上讨论 Android 相关的主题。
即使这样,我今天依然感觉跟不上 Android 整个生态系统的变化。可想而知,对于那些经验不足,需要指导的 Android 开发者而言,是多么地绝望。我现在已经无法想像,现在从头开始学习 Android 的感觉。当你好不容易学会了某个框架或者工具,觉得它很好用的时候,它或许就要过时了。现在也许是加入 Android 开发大家庭最坏的时候。Google 正为他们的“包容性”沾沾自喜,但这一切,对初学者来说,都是极其痛苦的。
Google 在 Android 框架中所做的事情,会导致大量的时间浪费。我们需要花费数小时的时间才能读完所有更改的内容,更别说在项目中应用它们了。我宁愿花时间来创造价值,而不是舍本逐末。
在本文中,我试图总结 Android 开发的现状,并对未来作出了一些预测。文章中,可能包含错误和漏掉一些重要信息,请随时在下面的评论中告知我。文章中的内容都是客观内容,虽然我提出了一些有争议观点,但我相信我是对的。
还有,在文章中,我引用了很多之前写的帖子,我并不是为了炫耀。而是让你能够阅读之前的预测与现在的状况进行对比,虽然那些文章在那个时候读起来很疯狂,就像现在你读本文一样,但是我的这些预测都是很准确的。当然,我也想说:“看,我说得对吧”。鉴于我发布的内容具有争议,当得知没有误导读者,我也会感到很欣慰。有时候,我也宁愿我的预测是错的,Google 正在为开发者着想。但是到目前为止,情况并非如此。
一如既往,感谢你的阅读。你可以在下面留言评论和提问。
[1] https://stackoverflow.com/questions/29197821/why-does-aosp-add-new-apis-to-support-libraries-without-adding-them-to-sdk
[2] https://developer.android.com/jetpack
[3] https://android-developers.googleblog.com/2019/11/unifying-background-task-scheduling-on.html
[4] https://issuetracker.google.com/issues/122098785
[5] https://youtu.be/UnJ3amzJM94
[6] https://android-review.googlesource.com/c/platform/frameworks/support/+/1169184/3/applicationpreferences/src/main/java/androidx/applicationpreferences/ApplicationPreferences.java
[7] https://stackoverflow.com/a/37551254/2463035
[8] https://www.techyourchance.com/dagger-android-dead/
[9] https://stackoverflow.com/a/30628530/2463035
[10] https://www.reddit.com/r/androiddev/comments/b908fr/can_someone_explain_to_me_why_aac_is_trying_to/
[11] https://android-review.googlesource.com/c/platform/frameworks/support/+/1159084
[12] https://www.techyourchance.com/android-fragment-lifecycle
[13] https://www.techyourchance.com/android-viewmodel-architecture-component-harmful/
[14] https://www.techyourchance.com/asynctask-deprecated/
[15] https://www.techyourchance.com/kotlin-coroutines-in-complex-scenarios/
[16] https://www.techyourchance.com/migrate-android-applications-to-kotlin-with-caution/
英文:The State of Native Android Development
链接:https://www.techyourchance.com/the-state-of-native-android-development-november-2019/
作者:Vasiliy Zukanov,独立 Android 开发及软件顾问
译者:罗昭成,Android 开发者