中国电信营业厅: 感受 Kotlin 的 "加速度"
"我们手上是一个很成熟的项目,所以毫无疑问需要保留 Java 代码,目前只会在新开发的页面中使用 Kotlin,并已经感受到了它带来的便利。随着功能的迭代,我们相信更多的功能会转而使用 Kotlin。" —— 付迎鑫,电信营业厅技术负责人
中国电信电子渠道运营中心,属于中国电信三大主渠道之一,负责电信线上渠道的管理与运营。电信营业厅 app 则是中国电信线上渠道的主要入口。目前该应用的注册用户超过 2 亿,月活跃用户接近 6,000 万,月交易额在 10 亿以上。
电信营业厅应用的技术团队所面临的挑战,基本都和 "速度" 有关:
- 电信营业厅 app 不是简单的工具应用,而是中国电信在线服务的官方品牌,并基于这个定位打造成了包括电商、互联网直播、阅读、音乐、影视、游戏、资讯、生活服务、公益事业的综合服务平台。要确保如此繁多的功能都流畅稳定地运行,对技术团队的开发效率都有十分高的要求。
- 庞大的用户群体也使得应用运行的硬件和平台十分多样,技术团队需要跟得上用户们更换新设备、更新操作系统的速度。
- 大型应用自然也会有庞大的历史资产,一旦需要对这些资产进行迭代,也需要尽可能降低时间成本。
而 Kotlin 带来的 "加速度",则让开发团队切实感受了一把 "推背感"。
第一脚油门总是需要慎重
2017 年上海,开发团队在谷歌开发者大会上了解到 Kotlin 技术框架已经日趋成熟,在看到很多主流应用纷纷开始使用 Kotlin 之后,团队便决定将 Kotlin 作为重点研究和学习的方向,并开始定期举办内部的学习和分享活动。
△ 电信营业厅技术团队核心成员于谷歌开发者大会。
左起: 付迎鑫 (电信营业厅技术负责人)、刘峻宇 (电信营业厅星播客项目经理)、曾皓 (电信营业厅 Android 项目经理)、张熠 (电信营业厅 Android 项目经理)、黄森燊 (电信营业厅 Android 开发工程师)
但对开发者们来说,感受一门语言最直接的方式,依然还是上手开发。于是团队决定先在中国电信渠道中心的内部应用 "电渠报表" 中使用 Kotlin 作为主打开发语言。
十分简洁的语法,对 lambda 表达式的支持,以及充分考虑了现代编程需求的架构,让团队 "打开了新世界的大门"。之后 Kotlin 很快就出现在了中国电信渠道中心的各个核心业务中,包括本文开头提到的电信营业厅应用,以及电信星播客应用。
"目前来看,项目整体已经有 20% 在使用 Kotlin,开发新功能的话 50% 的代码都是 Kotlin。" —— 付迎鑫,电信营业厅技术负责人
△ 用来 "小试牛刀 的电渠报表应用
开得快,开得稳
其实很多时候,"快" 和 "稳" 并不矛盾——疾驰的跑车如果时不时爆胎,那显然也是跑不快的。
空指针异常 (NPE) 导致的崩溃 (或 ANR) 就是让开发者和用户们沮丧的 "爆胎"。Kotlin 可以保护项目避免对可空类型进行误操作。如果类型检测正确,编译器还会进行自动类型转换,NPE 的出现概率降低了 80% 之多,项目稳定性和健壮性显著提高,更为对接和展示各省返回的业务数据打下了良好的基础。
Kotlin 的另一个关键新特性是协程,它是一个轻量级的线程,一个线程中可以创建任意个协程,线程的执行和结束是由操作系统调度的,而协程可以让开发者手动控制其执行和结束。在项目中,团队会结合使用 Retrofit 和协程来处理网络请求,从而更好地控制任务的执行,这样会比单纯使用线程更加节省资源,也更加高效。在使用协程后,团队得以降低首页各个频道接口调用所需的资源,接口调用周期也更加可控。目前电信营业厅的首页和商城等核心页面都是通过 Kotlin 打造出流畅的使用体验。
△ 电信营业厅应用的首页和商城页面
Kotlin 的 "快" 还体现在对代码的精简上。对于习惯了冗长 Java 代码的 Android 开发者来说,Kotlin 的 SAM (Single Abstract Method) 转换一下子缩减大量的模版代码可能会让他们不太适应——尤其是在通过 lambda 表达式实现 SAM 转换的时候。但更简洁、更有可读性的代码无疑可以让开发者的注意力更容易集中在业务逻辑上,而不是冗长的模版代码上。
另一个能大量精简代码的地方是控件绑定,以前在 Activity 中需要为绑定控件编写大量的代码 (没错,就是 "findViewById")。引入 Jetpack View Binding 之后,ID 可以直接当做变量使用,在 ViewBinding 推出之后,配合 Kotlin 能写出更加安全和简洁的代码。
是时候看看远方的风景了
使用 Kotlin 带来的另一个好处,就是进入 Android 平台新功能的 "快车道"。
比如 Android 10 的时候平台增加了对折叠屏设备的支持,但想要让用户在折叠/展开设备时感觉流畅,免不了需要让应用妥善保存界面状态和支持配置变更,用 Java 编写这种 "保存/读取配置" 的工作虽然可行,但 Kotlin 的 lambda 解构方式能够帮助开发者更加方便地对需要保存的实体类和相关配置进行修改和读取,代码更加精简,可读性也更好。
△ 电信营业厅的折叠态和展开态
在 Android 支持 5G 之后,开发团队可以通过 ConnectivityManager 类拓展的新方法为 5G 用户打造更加快速的网络体验。对那些流量敏感的用例,也可以直接使用 网络连接 API 来检测设备是否进行了高带宽连接,并能 检查连接是否计费。这时,开发团队大量使用了 Kotlin 的局部委托属性,使代码更加清晰明了。
来自团队的经验分享
从接触、了解 Kotlin,到逐步尝试,乃至正式采用,电信营业厅技术团队总结了一些第一手的经验,这里和大家分享。
- 在使用 Kotlin 前,首先要对项目组成员对 Kotlin 的熟悉程度做一个简单的评估。对于新项目来说,需要对项目本身工作量进行评估,如果时间规划上比较充裕,可以考虑引入 Kotlin,这也可以让开发团队在实践中更加了解 Kotlin;而对于老项目来说,就需要综合考虑兼容性、稳定性、维护性等其他相关因素。
- 需要为兼容性相关问题多预留一些解决时间,尤其是项目组成员对 Kotlin 还不那么熟悉的时候。
- 如果在开发过程中发现最新的 Kotlin 需要升级到 AndroidX,需要慎重推进。因为升级 AndroidX 又会和很多第三方库产生冲突,这时只能通过与第三方进行协调来解决问题。
"我们会继续加大在 Kotlin 上的投入,目标是在新项目中 100% 使用 Kotlin。" —— 付迎鑫,电信营业厅技术负责人
更简洁、更高效、更现代的 Kotlin,已经让电信营业厅技术团队感受到了真实的 "加速度"。您是否已经准备好进入 Android 开发的 "快车道" 了呢?
相关文章
- R8 编译器: 为 Kotlin 库和应用 "瘦身"
- 有关 Kotlin 具名参数形参传参顺序导致输出结果发生改变问题的一些探索
- Kotlin函数式编程
- 基于kotlin开发的验证码发送注册的app
- 【Kotlin】Kotlin 语言基础 ( 环境安装 | 变量 | 简单使用 | 函数 | 异常 | 递归 )
- 【Kotlin】扩展函数 ( 扩展函数声明 | 调用方式 | 与成员函数优先级 | 接收者空值处理 )
- 【Kotlin】扩展属性 ( 扩展变量属性 | 扩展常量属性 | 注意事项 | 本质分析 )
- 【错误记录】Kotlin 报错 ( Some kotlin libraries attached to this project were compiled with a newer kotlin )
- 【Kotlin 协程】Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )
- 【Kotlin】空安全 ⑥ ( 先决条件函数 | checkNotNull 函数 | require 函数 | requireNotNull 函数 | error 函数 | assert 函数 )
- 【Kotlin】字符串操作 ① ( 截取字符串函数 substring | 拆分字符串函数 split | 解构语法特性 )
- 【Kotlin】标准库函数 ③ ( with 标准库函数 | also 标准库函数 )
- 【Kotlin】:: 双冒号操作符详解 ( 获取类的引用 | 获取对象类型的引用 | 获取函数的引用 | 获取属性的引用 | Java 中的 Class 与 Kotlin 中的 KClass )
- 学习开源操作系统Linux及现代编程语言Kotlin的必要性(linuxkotlin)