本文讲的是【译】将 Android 项目迁移到 Kotlin 语言,
- 原文地址:Migrating an Android project to Kotlin
- 原文作者:Ben Weiss
- 译文出自:掘金翻译计划
- 本文永久链接:github.com/xitu/gold-m…
- 译者:wilsonandusa
- 校对者:phxnirvana, Zhiw
不久前我们开源了 Topeka,一个 Android 小测试程序。
这个程序是用 integration tests 和 unit tests 进行测试的, 而且本身全部是用 Java 写的。至少以前是这样的...
圣彼得堡岸边的那个岛屿叫什么?
2017年谷歌在开发者大会上官方宣布 支持 Kotlin 编程语言。从那时起,我便开始移植 Java 代码,同时在过程中学习 Kotlin。
从技术角度上来讲,这次的移植并不是必须的,程序本身是十分稳定的,而(这次移植)主要是为了满足我的好奇心。Topeka 成为了我学习一门新语言的媒介。
如果你好奇的话可以直接来看 GitHub 上的源代码。
目前 Kotlin 代码在一个独立的分支上,但我们计划在未来某个时刻将其合并到主代码中。
这篇文章涵盖了我在迁移代码过程中发现的一些关键点,以及 Android 开发新语言时有用的小窍门。
看上去依旧一样
关键的几点
- Kotlin 是一门有趣而强大的语言
- 多测试才能心安
- 平台受限的情况很少
移植到 Kotlin 的第一步
虽然不可能像 Bad Android Advice 所说的那么简单,但至少是个不错的出发点。
第一步和第二步对于学好 Kotlin 来说确实很有用。
然而第三步就要看我个人的造化了。
对于 Topeka 来说实际步骤如下:
- 学好 Kotlin 的基础语法
- 通过使用 Koan 来逐步熟悉这门语言
- 使用 “⌥⇧⌘K” 保证(转化后的文件)仍然能一个个通过测试
- 修改 Kotlin 文件使其更加符合语言习惯
- 重复第四步直到你和审核你代码的人都满意
- 完工并上交
互通性
一步步去做是很明智的做法。
Kotlin 编译为 Java 字节码后两种语言可以互相通用。而且同一个项目中两种语言可以共存,所以并不需要把全部代码都移植成为另一种语言。
但如果你本来就想这么做,那么重复的改写就是有意义的,这样你在迁移代码时可以尽量地维持项目的稳定性,并在此过程中有所收获。
多做测试才能更加安心
搭配使用单元和集成测试的好处很多。在绝大多数情况下,这些测试是用来确保当前修改没有损坏现有的功能。
我选择在一开始使用一个不是很复杂的数据类。在整个项目中我一直在用这些类,它们的复杂性相比来说很低。这样来看在学习新语言的过程中这些类就成为了最理想的出发点。
在通过使用 Android Studio 自带的 Kotlin 代码转换器移植一部分代码后,我开始执行并通过测试,直到最终将测试本身也移植为 Kotlin 代码。
如果没有测试的话,我在每次改写后都需要对可能受影响的功能手动进行测试。自动化的测试在我移植代码的过程中显得更加快捷方便。
所以,如果你还没有对你的应用进行正确测试的话,以上就是你需要这么做的又一个原因。
生成的代码并不是每一次都看起来很棒!!
在完成最开始几乎自动化的移植代码之后,我开始学习 Kotlin 代码风格指南。 这使我发现还有一条很长的路要走。
总体来讲,代码生成器用起来很不错。尽管有很多语言特征和风格在转换过程中没有被使用,但翻译语言本来就是件很棘手的事,这么做可能更好一些,尤其是当这门语言所包含很多的特征或者可以通过不同方式进行表达的时候。
如果想要了解更多有关 Kotlin 转换器的内容, Benjamin Baxter 写过一些他自己的经历:
️
我发现自动转换会生成很多的 ?
和 !!
。
这些符号是用来定义可为空的数值和保证其不为空值的。他们反而会导致 空指针异常
。
我不禁想到一条很恰当的名言
“过多使用感叹号,” 他一边摇头一边说道, ”是心理不正常的表现。” — Terry Pratchett
在大部分情况下它不会成为空值,所以我们不需要使用空值的检查。同时也没必要通过构造器来直接初始所有的数值,可以使用 lateinit
或者委托来代替初始的流程。
然而这些方法也不是万能的:
看来我得重新把 view 定义为可为空值。
在其他情况下你还是得检查是否 null
存在。如果存在 supportActionBar
的话,*supportActionBar*?.setDisplayShowTitleEnabled(false)
才会执行问号以后的代码。
这意味着更少的基于 null 检查的 if 条件声明。
直接在非空数值上使用 stdlib 函数非常方便:
toolbarBack?.let {
it.scaleX = 0f
it.scaleY = 0f
}
大规模地使用它...
变得越来越符合语言习惯
因为我们可以通过审核者的反馈不断地改写生成的代码来使其变得更加符合语言的习惯。这使代码更加简洁并且提升了可读性。以上特点可以证明 Kotlin 是门很强大的语言,
来看看我曾经遇到过的几个例子吧。
少读点儿并不一定是件坏事
我们拿 adapter 里面的 getView
来举例:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
convertView = createView(parent);
}
bindView(convertView);
return convertView;
}
Java 中的 getView
override fun getView(position: Int, convertView: View?, parent: ViewGroup) =
(convertView ?: createView(parent)).also { bindView(it) }
Kotlin 的 getView
这两段代码在做同一件事:
先检查 convertView
是否为 null
,然后在 createView(...)
里面创建一个新的 view
,或者返回 convertView
。同时在最后调用 bindView(...)
.
两端代码都很清晰,不过能从八行代码减到只有两行确实让我很惊讶。