- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章使用 Kotlin 重写 AOSP 日历应用由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
两年前,Android 开源项目 (AOSP) 应用团队开始使用 Kotlin 替代 Java 重构 AOSP 应用。之所以重构主要有两个原因: 一是确保 AOSP 应用能够遵循 Android 最佳实践,另外则是提供优先使用 Kotlin 进行应用开发的良好范例。Kotlin 之所以具有强大的吸引力,原因之一是其简洁的语法,很多情况下用 Kotlin 编写的代码块的代码数量相比于功能相同的 Java 代码块要更少一些。此外,Kotlin 这种具有丰富表现力的编程语言还具有其他各种优点,例如
AOSP 团队在去年夏天发表了一篇文章,详细介绍了 AOSP 桌面时钟应用的转换过程。而今年,我们将 AOSP 日历应用从 Java 转换成了 Kotlin。在这次转换之前,应用的代码行数超过 18,000 行,在转换后代码库减少了约 300 行。在这次的转换中,我们沿袭了同 AOSP 桌面时钟转换过程中类似的技术,充分利用了 Kotlin 与 Java 语言的互操作性,对代码文件一一进行了转换,并在过程中使用独立的构建目标将 Java 代码文件替换为对应的 Kotlin 代码文件。因为团队中有两个人在进行此项工作,所以我们在 Android.bp 文件中为每个人创建了一个 exclude_srcs 属性,这样两个人就可以在减少代码合并冲突的前提下,都能够同时进行重构并推送代码。此外,这样还能允许我们进行增量测试,快速定位错误出现在哪些文件.
在转换任意给定的文件时,我们一开始先使用 Android Studio Kotlin 插件中提供的从 Java 到 Kotlin 的自动转换工具。虽然该插件成功帮助我们转换了大部份的代码,但是还是会遇到一些问题,需要开发者手动解决。需要手动更改的部分,我们将会在本文接下来的章节中列出.
在将每个文件转换为 Kotlin 之后,我们手动测试了日历应用的 UI 界面,运行了单元测试,并运行了 Compatibility Test Suite (CTS) 的子集来进行功能验证,以确保不需要再进行任何的回归测试.
上面提到,在使用自动转换工具之后,有一些反复出现的问题需要手动定位解决。在 AOSP 桌面时钟文章中,详细介绍了其中遇到的一些问题以及解决方法。如下列出了一些在进行 AOSP 日历转换过程中遇到的问题.
我们遇到的问题之一是 Kotlin 父类和子类之间的相互调用。在 Kotlin 中,要将一个类标记为可继承,必须得在类的声明中添加 open 关键字,对于父类中被子类覆盖的方法也要这样做。但是在 Java 中的继承是不需要使用到 open 关键字的。由于 Kotlin 和 Java 能够相互调用,这个问题直到大部分代码文件转换到了 Kotlin 才出现.
例如,在下面的代码片段中,声明了一个继承于 SimpleWeeksAdapter 的类
由于代码文件的转换过程是一次一个文件进行的,即使是完全将 SimpleWeeksAdapter.kt 文件转换成 Kotlin,也不会在其类的声明中出现 open 关键词,这样就会导致一个错误。所以之后需要手动进行 open 关键词的添加,以便让 SimpleWeeksAdapter 类可以被继承。这个特殊的类声明如下所示
同样地,子类中覆盖父类的方法也必须使用 override 修饰符来进行标记。在 Java 中,这是通过 @Override 注解来实现的。然而,虽然在 Java 中有相应的注解实现版本,但是自动转换过程中并没有为 Kotlin 方法声明中添加 override 修饰符。解决的办法是在所有适当的地方手动添加 override 修饰符.
在重构过程中,我们还遇到了一个属性覆写的异常问题,当一个子类声明了一个变量,而在父类中存在一个非私有的同名变量时,我们需要添加一个 override 修饰符。然而,即使子类的变量同父类变量的类型不同,也仍然要添加 override 修饰符。在某些情况下,添加 override 仍不能解决问题,尤其是当子类的类型完全不同的时候。事实上,如果类型不匹配,在子类的变量前添加 override 修饰符,并在父类的变量前添加 open 关键字,会导致一个错误
这个报错很让人疑惑,因为在 Java 中,以下代码可以正常编译
而在 Kotlin 中相应的代码就会报上面提到的错误
这个问题很有意思,目前我们通过在子类中对变量重命名来规避了这个冲突。上面的 Java 代码会被 Android Studio 目前提供的代码转换器转换为有问题的 Kotlin 代码,这甚至被报告为是一个 bug 了.
在我们转换的所有文件中,自动转换工具都倾向于将 Java 代码中的所有 import 语句截断为 Kotlin 文件中的第一行。最开始这导致了一些很让人抓狂的错误,编译器会在整个代码中报 "unknown references" 的错误。在意识到这个问题后,我们开始手动地将 Java 中的 import 语句粘贴到 Kotlin 代码文件中,并单独对其进行转换.
默认情况下,Kotlin 会自动地为类中的实例变量生成 getter 和 setter 方法。然而,有些时候我们希望一个变量仅仅只是一个简单的 Java 成员变量,这可以通过使用 @JvmField 注解来实现.
@JvmField 注解的作用是 "指示 Kotlin 编译器不要为这个属性生成 getter 和 setter 方法,并将其作为一个成员变量允许其被公开访问"。这个注解在 CalendarData 类中特别有用,它包含了两个 static final 变量。通过对使用 val 声明的只读变量使用 @JvmField 注解,我们确保了这些变量可以作为成员变量被其他类访问,从而实现了 Java 和 Kotlin 之间的兼容性.
在 Kotlin 对象中定义的函数必须使用 @JvmStatic 进行标记,以允许在 Java 代码中通过方法名,而非实例化来对它们进行调用。也就是说,这个注解使其具有了类似 Java 的方法行为,即能够通过类名调用方法。根据 Kotlin 的文档,"编译器会为对象的外部类生成一个静态方法,而对于对象本身会生成一个实例方法。"我们在 Utils 文件中遇到了这个问题,当完成转换后,Java 类就变成了 Kotlin 对象。随后,所有在对象中定义的方法都必须使用 @JvmStatic 标记,这样就允许在其他文件中使用 Utils.method() 这样的语法来进行调用。值得一提的是,在类名和方法名之间使用 .INSTANCE (即 Utils.INSTANCE.method()) 也是一种选择,但是这不太符合常见的 Java 语法,需要改变所有对 Java 静态方法的调用.
所有的基准测试都是在一台 96 核、176 GiB 内存的机器上进行的。本项目中分析用到的主要指标有所减少的代码行数、目标 APK 的文件大小、构建时间和首屏从启动到显示的时间。在对上述每个因素进行分析的同时,我们还收集了每个参数的数据并以表格的方式进行了展示.
从 Java 完全转换到 Kotlin 后,代码行数从 18,004 减少到了 17,729。这比原来的 Java 代码量减少了大约 1.5%。虽然减少的代码量并不可观,但对于一些大型应用来说,这种转换对于减少代码行数的效果可能更为显著,可参阅 AOSP 桌面时钟文中所举的例子.
使用 Kotlin 编写的应用 APK 大小是 2.7 MB,而使用 Java 编写的应用 APK 大小是 2.6 MB。可以说这个差异基本可以忽略不计了,由于包含了一些额外的 Kotlin 库,所以 APK 体积上的增加,实际上是可以预期的。这种大小的增加可以通过使用 Proguard 或 R8 来进行优化.
Kotlin 和 Java 应用的构建时间是通过取 10 次从零进行完整构建的时间的平均值来计算的 (不包含异常值),Kotlin 应用的平均构建时间为 13 分 27 秒,而 Java 应用的平均构建时间为 12 分 6 秒。据一些资料 (如 "Java 和 Kotlin 的区别" 以及 "Kotlin 和 Java 在编译时间上的对比") 显示,Kotlin 的编译时间事实上比 Java 要更耗时,特别是对于从零开始的构建。一些分析断言,Java 的编译速度会快 10-15%,又有一些分析称这一数据为 15-20%。拿我们的例子进行从零开始完整构建所花费的时间来说,Java 的编译速度比 Kotlin 快 11.2%,尽管这个微小的差异并不在上述范围内,但这有可能是因为 AOSP 日历是一个相对较小的应用,仅有 43 个类。尽管从零开始的完整构建比较慢,但是 Kotlin 仍然在其他方面占有优势,这些优势更应该被考虑到。例如,Kotlin 相对于 Java,更简洁的语法通常可以保证较少的代码量,这使得 Kotlin 代码库更易维护。此外,由于 Kotlin 是一种更为安全有效的编程语言,我们可以认为完整构建时间较慢的问题可以忽略不计.
我们使用了这种方法来测试应用从启动到完全显示首屏所需要的时间,经过 10 次试验后我们发现,使用 Kotlin 应用的平均时间约为 197.7 毫秒,而 Java 的则为 194.9 毫秒。这些测试都是在 Pixel 3a XL 设备上进行的。从这个测试结果可以得出结论,与 Kotlin 应用相比,Java 应用可能具有微小的优势;然而,由于平均时间非常接近,这个差异几乎可以忽略不计。因此,可以说 AOSP 日历应用转换到 Kotlin,并没有对应用的初始启动时间产生负面影响.
将 AOSP 日历应用转换为 Kotlin 大约花了 1.5 个月 (6 周) 的时间,由 2 名实习生负责该项目的实施。一旦我们对代码库更加熟悉并更加善于解决反复出现的编译时、运行时和语法问题时,效率肯定会变得更高。总的来说,这个特殊的项目成功地展示了 Kotlin 如何影响现有的 Android 应用,并在对 AOSP 应用进行转换的路途中迈出了坚实的一步.
原文地址:https://mp.weixin.qq.com/s/zYF1b6siQazRttrmXWx1ig 。
最后此篇关于使用 Kotlin 重写 AOSP 日历应用的文章就讲到这里了,如果你想了解更多关于使用 Kotlin 重写 AOSP 日历应用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在 AOSP 4.0.4 分支上工作,并为 PandaBoard 平台做一些定制。我查看了用于构建 Android 文件系统镜像的 ARM 交叉工具链,我看到了 2 个主要变体。 arm-eabi
有什么方法可以阻止用户在自定义 android 操作系统中安装来自未知来源的应用程序? 我正在尝试使用 AOSP 源创建 Android 操作系统的自定义变体,在其中我希望允许用户仅安装来自我在构建期
如何在 AOSP 构建中查看详细的编译命令? ndk-build 提供 V=1 选项。从源代码构建怎么样?我可以输入类似于 的内容吗 . build/envsetup.sh lunch make li
在完全配置 AOSP 之后。我尝试使用 make -j4 构建它。但是我收到以下错误: ============================================ PLATFORM_
我是 Android retrofit 的新手,我想知道如何在不修改我自己的设备(摩托罗拉 Moto G 2014)的情况下构建 AOSP。 我已经阅读了 Google 指南,但它仅显示了如何为 Ne
我正在为 Android 8.1 版构建 AOSP,我想实现自己的应用商店,因此需要将 apk 安装到系统上。 到目前为止,我看到的唯一方法是使用如下内容: val intent = Intent(I
由于 Android studio 3.5 未检测到系统镜像,我正在尝试构建汽车模拟器。我已经在 Android 8 和 9 中尝试过并下载了所有工具。如何在 AOSP 中构建汽车模拟器? 最佳答案
我有一个 AOSP 5.1 - 在我的 Allwinner A33 设备上构建。 长按“电源按钮”时,设备会启动“关机”程序。它显示了一个对话框“关闭电源”以及一个微调器(见屏幕截图)。这会持续约 3
我正在从 AOSP 源代码构建自定义 rom 我首先决定通过下载并导入到 Android Studio 来从 AOSP 源代码树编辑一些 AOSP 应用 我选择了 ExactCalculator 进行
我正在尝试在 Mac OS 上使用 make -jN 构建 aosp,但它以下一个错误结束: required: BlockingQueue found: BlockingQueue N
我可以成功下载并构建 Android 操作系统源代码,并且操作系统镜像运行良好。 操作系统使用“build/target/product/security”下的平台证书进行签名,我使用相同的证书对我的
我已经从 source.android.com 下载了 Android 源代码并构建了它,并且能够在模拟器上成功运行它。 现在我想为 Android 添加新的系统服务。考虑到这是我第一次这样做,我对构
根据安卓指南: 1. 下载仓库 2. repo 初始化 3. repo 同步 我在磁盘中得到了Android 7.1.1的源代码 午餐组合时出现问题 You're building on Darwin
我正在阅读 Android 开源项目中的代码,我看到方法名称具有有趣的结尾,如下所示:addSharedUserLPw()(在 com.android.server.pm.Settings 中)ins
这是与 device-node-access-permissions-in-linux 类似的帖子6年前没有答案。 我在 /dev/magic-i2c 使用 misc_register() 创建了一个
首先,我是 Android 构建的新手,只想从简单的东西开始,所以我想按照索尼关于如何为解锁设备构建 AOSP 的指南为我的 Xperia X (F5121) 构建 AOSP 8.0。 因此,要开始构
我正在为类似平板电脑的设备构建 Android AOSP 6 (Marshmallow),该设备是永久安装的(例如工业部署)并且没有电池。但是,当我给它通电时,它会显示充电指示灯和 0% 的电量读数。
我已经下载了 Lollipop 5.0 的 AOSP 源代码。在 API 级别 21 中,在蓝牙低功耗扫描设置下,有三个用于扫描蓝牙设备的选项 - SCAN_MODE_BALANCED、SCAN_MO
为了熟悉 AOSP,我打算按照 official documentation 构建图像并在模拟器上运行它。 . 设置 Ubuntu 16.04 VM 后,我使用以下命令: repo init -u h
我正在 build AOSP 4.2 Jelly Bean .当我构建默认值时一切正常 full-eng配置并在模拟器上运行。 我需要构建自定义设备并运行它(在 emulator 上 - 用于测试它是
我是一名优秀的程序员,十分优秀!