成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用 Kotlin 重寫 AOSP 日歷應(yīng)用

移動開發(fā) Android
Kotlin 之所以具有強(qiáng)大的吸引力,原因之一是其簡潔的語法,很多情況下用 Kotlin 編寫的代碼塊的代碼數(shù)量相比于功能相同的 Java 代碼塊要更少一些。此外,Kotlin 這種具有豐富表現(xiàn)力的編程語言還具有其他各種優(yōu)點(diǎn)。

兩年前,Android 開源項(xiàng)目 (AOSP) 應(yīng)用團(tuán)隊(duì)開始使用 Kotlin 替代 Java 重構(gòu) AOSP 應(yīng)用。之所以重構(gòu)主要有兩個原因: 一是確保 AOSP 應(yīng)用能夠遵循 Android 最佳實(shí)踐,另外則是提供優(yōu)先使用 Kotlin 進(jìn)行應(yīng)用開發(fā)的良好范例。Kotlin 之所以具有強(qiáng)大的吸引力,原因之一是其簡潔的語法,很多情況下用 Kotlin 編寫的代碼塊的代碼數(shù)量相比于功能相同的 Java 代碼塊要更少一些。此外,Kotlin 這種具有豐富表現(xiàn)力的編程語言還具有其他各種優(yōu)點(diǎn),例如:

[[424403]]

  • 空安全: 這一概念可以說是根植于 Kotlin 之中,從而幫助避免破壞性的空指針異常;
  • 并發(fā): 正如 Google I/O 2019 中關(guān)于 Android 的描述,結(jié)構(gòu)化并發(fā) (structured concurrency) 能夠允許使用協(xié)程簡化后臺的任務(wù)管理;
  • 兼容 Java: 尤其是在這次的重構(gòu)項(xiàng)目中,Kotlin 與 Java 語言的兼容性能夠讓我們一個文件一個文件地進(jìn)行 Kotlin 轉(zhuǎn)換。

AOSP 團(tuán)隊(duì)在去年夏天發(fā)表了一篇文章,詳細(xì)介紹了 AOSP 桌面時鐘應(yīng)用的轉(zhuǎn)換過程。而今年,我們將 AOSP 日歷應(yīng)用從 Java 轉(zhuǎn)換成了 Kotlin。在這次轉(zhuǎn)換之前,應(yīng)用的代碼行數(shù)超過 18,000 行,在轉(zhuǎn)換后代碼庫減少了約 300 行。在這次的轉(zhuǎn)換中,我們沿襲了同 AOSP 桌面時鐘轉(zhuǎn)換過程中類似的技術(shù),充分利用了 Kotlin 與 Java 語言的互操作性,對代碼文件一一進(jìn)行了轉(zhuǎn)換,并在過程中使用獨(dú)立的構(gòu)建目標(biāo)將 Java 代碼文件替換為對應(yīng)的 Kotlin 代碼文件。因?yàn)閳F(tuán)隊(duì)中有兩個人在進(jìn)行此項(xiàng)工作,所以我們在 Android.bp 文件中為每個人創(chuàng)建了一個 exclude_srcs 屬性,這樣兩個人就可以在減少代碼合并沖突的前提下,都能夠同時進(jìn)行重構(gòu)并推送代碼。此外,這樣還能允許我們進(jìn)行增量測試,快速定位錯誤出現(xiàn)在哪些文件。

在轉(zhuǎn)換任意給定的文件時,我們一開始先使用 Android Studio Kotlin 插件中提供的從 Java 到 Kotlin 的自動轉(zhuǎn)換工具。雖然該插件成功幫助我們轉(zhuǎn)換了大部份的代碼,但是還是會遇到一些問題,需要開發(fā)者手動解決。需要手動更改的部分,我們將會在本文接下來的章節(jié)中列出。

在將每個文件轉(zhuǎn)換為 Kotlin 之后,我們手動測試了日歷應(yīng)用的 UI 界面,運(yùn)行了單元測試,并運(yùn)行了 Compatibility Test Suite (CTS) 的子集來進(jìn)行功能驗(yàn)證,以確保不需要再進(jìn)行任何的回歸測試。

自動轉(zhuǎn)換之后的步驟

上面提到,在使用自動轉(zhuǎn)換工具之后,有一些反復(fù)出現(xiàn)的問題需要手動定位解決。在 AOSP 桌面時鐘文章中,詳細(xì)介紹了其中遇到的一些問題以及解決方法。如下列出了一些在進(jìn)行 AOSP 日歷轉(zhuǎn)換過程中遇到的問題。

用 open 關(guān)鍵詞標(biāo)記父類

我們遇到的問題之一是 Kotlin 父類和子類之間的相互調(diào)用。在 Kotlin 中,要將一個類標(biāo)記為可繼承,必須得在類的聲明中添加 open 關(guān)鍵字,對于父類中被子類覆蓋的方法也要這樣做。但是在 Java 中的繼承是不需要使用到 open 關(guān)鍵字的。由于 Kotlin 和 Java 能夠相互調(diào)用,這個問題直到大部分代碼文件轉(zhuǎn)換到了 Kotlin 才出現(xiàn)。

例如,在下面的代碼片段中,聲明了一個繼承于 SimpleWeeksAdapter 的類:

  1. class MonthByWeekAdapter(context: Context?, params: 
  2.     HashMap<String?, Int?>) : SimpleWeeksAdapter(context as Context, params) {//方法體} 

由于代碼文件的轉(zhuǎn)換過程是一次一個文件進(jìn)行的,即使是完全將 SimpleWeeksAdapter.kt 文件轉(zhuǎn)換成 Kotlin,也不會在其類的聲明中出現(xiàn) open 關(guān)鍵詞,這樣就會導(dǎo)致一個錯誤。所以之后需要手動進(jìn)行 open 關(guān)鍵詞的添加,以便讓 SimpleWeeksAdapter 類可以被繼承。這個特殊的類聲明如下所示:

  1. open class SimpleWeeksAdapter(context: Context, params: HashMap?) {//方法體} 

override 修飾符

同樣地,子類中覆蓋父類的方法也必須使用 override 修飾符來進(jìn)行標(biāo)記。在 Java 中,這是通過 @Override 注解來實(shí)現(xiàn)的。然而,雖然在 Java 中有相應(yīng)的注解實(shí)現(xiàn)版本,但是自動轉(zhuǎn)換過程中并沒有為 Kotlin 方法聲明中添加 override 修飾符。解決的辦法是在所有適當(dāng)?shù)牡胤绞謩犹砑? override 修飾符。

覆寫父類中的屬性

在重構(gòu)過程中,我們還遇到了一個屬性覆寫的異常問題,當(dāng)一個子類聲明了一個變量,而在父類中存在一個非私有的同名變量時,我們需要添加一個 override 修飾符。然而,即使子類的變量同父類變量的類型不同,也仍然要添加 override 修飾符。在某些情況下,添加 override 仍不能解決問題,尤其是當(dāng)子類的類型完全不同的時候。事實(shí)上,如果類型不匹配,在子類的變量前添加 override 修飾符,并在父類的變量前添加 open 關(guān)鍵字,會導(dǎo)致一個錯誤:

  1. type of *property name* doesn’t match the type of the overridden var-property 

這個報錯很讓人疑惑,因?yàn)樵?Java 中,以下代碼可以正常編譯:

  1. public class Parent { 
  2.     int num = 0; 
  3.  
  4. class Child extends Parent { 
  5.     String num = "num"

而在 Kotlin 中相應(yīng)的代碼就會報上面提到的錯誤:

  1. class Parent { 
  2.     var num: Int = 0 
  3.  
  4. class Child : Parent() { 
  5.     var num: String = "num" 

這個問題很有意思,目前我們通過在子類中對變量重命名來規(guī)避了這個沖突。上面的 Java 代碼會被 Android Studio 目前提供的代碼轉(zhuǎn)換器轉(zhuǎn)換為有問題的 Kotlin 代碼,這甚至被報告為是一個 bug 了。

import 語句

在我們轉(zhuǎn)換的所有文件中,自動轉(zhuǎn)換工具都傾向于將 Java 代碼中的所有 import 語句截斷為 Kotlin 文件中的第一行。最開始這導(dǎo)致了一些很讓人抓狂的錯誤,編譯器會在整個代碼中報 "unknown references" 的錯誤。在意識到這個問題后,我們開始手動地將 Java 中的 import 語句粘貼到 Kotlin 代碼文件中,并單獨(dú)對其進(jìn)行轉(zhuǎn)換。

暴露成員變量

默認(rèn)情況下,Kotlin 會自動地為類中的實(shí)例變量生成 getter 和 setter 方法。然而,有些時候我們希望一個變量僅僅只是一個簡單的 Java 成員變量,這可以通過使用 @JvmField 注解來實(shí)現(xiàn)。

@JvmField 注解的作用是 "指示 Kotlin 編譯器不要為這個屬性生成 getter 和 setter 方法,并將其作為一個成員變量允許其被公開訪問"。這個注解在 CalendarData 類中特別有用,它包含了兩個 static final 變量。通過對使用 val 聲明的只讀變量使用 @JvmField 注解,我們確保了這些變量可以作為成員變量被其他類訪問,從而實(shí)現(xiàn)了 Java 和 Kotlin 之間的兼容性。

對象中的靜態(tài)方法

在 Kotlin 對象中定義的函數(shù)必須使用 @JvmStatic 進(jìn)行標(biāo)記,以允許在 Java 代碼中通過方法名,而非實(shí)例化來對它們進(jìn)行調(diào)用。也就是說,這個注解使其具有了類似 Java 的方法行為,即能夠通過類名調(diào)用方法。根據(jù) Kotlin 的文檔,"編譯器會為對象的外部類生成一個靜態(tài)方法,而對于對象本身會生成一個實(shí)例方法。"我們在 Utils 文件中遇到了這個問題,當(dāng)完成轉(zhuǎn)換后,Java 類就變成了 Kotlin 對象。隨后,所有在對象中定義的方法都必須使用 @JvmStatic 標(biāo)記,這樣就允許在其他文件中使用 Utils.method() 這樣的語法來進(jìn)行調(diào)用。值得一提的是,在類名和方法名之間使用 .INSTANCE (即 Utils.INSTANCE.method()) 也是一種選擇,但是這不太符合常見的 Java 語法,需要改變所有對 Java 靜態(tài)方法的調(diào)用。

性能評估分析

所有的基準(zhǔn)測試都是在一臺 96 核、176 GiB 內(nèi)存的機(jī)器上進(jìn)行的。本項(xiàng)目中分析用到的主要指標(biāo)有所減少的代碼行數(shù)、目標(biāo) APK 的文件大小、構(gòu)建時間和首屏從啟動到顯示的時間。在對上述每個因素進(jìn)行分析的同時,我們還收集了每個參數(shù)的數(shù)據(jù)并以表格的方式進(jìn)行了展示。

減少的代碼行數(shù)

 

 

從 Java 完全轉(zhuǎn)換到 Kotlin 后,代碼行數(shù)從 18,004 減少到了 17,729。這比原來的 Java 代碼量減少了大約 1.5%。雖然減少的代碼量并不可觀,但對于一些大型應(yīng)用來說,這種轉(zhuǎn)換對于減少代碼行數(shù)的效果可能更為顯著,可參閱 AOSP 桌面時鐘文中所舉的例子。

 

目標(biāo) APK 大小

 

使用 Kotlin 編寫的應(yīng)用 APK 大小是 2.7 MB,而使用 Java 編寫的應(yīng)用 APK 大小是 2.6 MB。可以說這個差異基本可以忽略不計(jì)了,由于包含了一些額外的 Kotlin 庫,所以 APK 體積上的增加,實(shí)際上是可以預(yù)期的。這種大小的增加可以通過使用 Proguard 或 R8 來進(jìn)行優(yōu)化。

編譯時間

 

Kotlin 和 Java 應(yīng)用的構(gòu)建時間是通過取 10 次從零進(jìn)行完整構(gòu)建的時間的平均值來計(jì)算的 (不包含異常值),Kotlin 應(yīng)用的平均構(gòu)建時間為 13 分 27 秒,而 Java 應(yīng)用的平均構(gòu)建時間為 12 分 6 秒。據(jù)一些資料 (如 "Java 和 Kotlin 的區(qū)別" 以及 "Kotlin 和 Java 在編譯時間上的對比") 顯示,Kotlin 的編譯時間事實(shí)上比 Java 要更耗時,特別是對于從零開始的構(gòu)建。一些分析斷言,Java 的編譯速度會快 10-15%,又有一些分析稱這一數(shù)據(jù)為 15-20%。拿我們的例子進(jìn)行從零開始完整構(gòu)建所花費(fèi)的時間來說,Java 的編譯速度比 Kotlin 快 11.2%,盡管這個微小的差異并不在上述范圍內(nèi),但這有可能是因?yàn)?AOSP 日歷是一個相對較小的應(yīng)用,僅有 43 個類。盡管從零開始的完整構(gòu)建比較慢,但是 Kotlin 仍然在其他方面占有優(yōu)勢,這些優(yōu)勢更應(yīng)該被考慮到。例如,Kotlin 相對于 Java,更簡潔的語法通常可以保證較少的代碼量,這使得 Kotlin 代碼庫更易維護(hù)。此外,由于 Kotlin 是一種更為安全有效的編程語言,我們可以認(rèn)為完整構(gòu)建時間較慢的問題可以忽略不計(jì)。

首屏顯示的時間

 

我們使用了這種方法來測試應(yīng)用從啟動到完全顯示首屏所需要的時間,經(jīng)過 10 次試驗(yàn)后我們發(fā)現(xiàn),使用 Kotlin 應(yīng)用的平均時間約為 197.7 毫秒,而 Java 的則為 194.9 毫秒。這些測試都是在 Pixel 3a XL 設(shè)備上進(jìn)行的。從這個測試結(jié)果可以得出結(jié)論,與 Kotlin 應(yīng)用相比,Java 應(yīng)用可能具有微小的優(yōu)勢;然而,由于平均時間非常接近,這個差異幾乎可以忽略不計(jì)。因此,可以說 AOSP 日歷應(yīng)用轉(zhuǎn)換到 Kotlin,并沒有對應(yīng)用的初始啟動時間產(chǎn)生負(fù)面影響。

結(jié)論

將 AOSP 日歷應(yīng)用轉(zhuǎn)換為 Kotlin 大約花了 1.5 個月 (6 周) 的時間,由 2 名實(shí)習(xí)生負(fù)責(zé)該項(xiàng)目的實(shí)施。一旦我們對代碼庫更加熟悉并更加善于解決反復(fù)出現(xiàn)的編譯時、運(yùn)行時和語法問題時,效率肯定會變得更高。總的來說,這個特殊的項(xiàng)目成功地展示了 Kotlin 如何影響現(xiàn)有的 Android 應(yīng)用,并在對 AOSP 應(yīng)用進(jìn)行轉(zhuǎn)換的路途中邁出了堅(jiān)實(shí)的一步。

責(zé)任編輯:未麗燕 來源: Android 開發(fā)者
相關(guān)推薦

2011-01-21 17:00:49

Thunderbird日歷

2015-06-08 09:39:17

AOSPAndroid M

2024-01-11 15:54:55

eTS語言TypeScript應(yīng)用開發(fā)

2011-01-21 17:43:21

Thunderbird日歷

2013-10-23 15:13:22

2024-01-08 09:00:00

開發(fā)DSLKotlin

2020-02-20 14:40:53

Vim郵件開源

2013-10-21 18:13:06

WiresharkQtQt重寫

2017-05-22 11:09:53

KotlinAndroid

2021-05-19 10:43:28

惡意軟件Rust的Buer

2018-04-25 10:46:05

Linux命令行日歷

2021-03-15 09:00:00

開發(fā)JavaKotlin

2021-02-04 12:06:03

HTTPDRust服務(wù)器

2011-04-08 10:02:06

日歷Windows Pho

2023-06-20 07:01:00

Outlook微軟

2020-02-26 13:47:57

Emacs電子郵件開源

2018-04-24 15:00:59

Kotlin語言函數(shù)

2010-11-18 17:08:44

Oracle使用SQL

2023-03-07 10:43:52

AndroidFramework測試

2012-05-31 14:46:32

jQuery
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 三级av网址 | 在线看黄免费 | 日本在线视频一区二区 | 9久久婷婷国产综合精品性色 | a免费视频| 国产精品国色综合久久 | 精品视频一区二区在线观看 | 日韩免费高清视频 | 五月天天色 | 亚洲一区二区三区久久久 | 大香在线伊779 | 91在线看网站 | 在线视频 亚洲 | 日韩午夜在线观看 | 欧美精品一区二区在线观看 | 一区二区三区四区日韩 | 久久久久久国产精品免费免费男同 | 性欧美精品一区二区三区在线播放 | 一区二区三区国产视频 | 欧美成人激情 | 久久一二 | 91麻豆精品国产91久久久更新资源速度超快 | 久久亚洲欧美日韩精品专区 | 久久久久久久综合 | 九九福利 | 在线日韩精品视频 | 中文字幕亚洲视频 | 日韩在线国产 | 精品国产欧美一区二区三区不卡 | 欧美综合国产精品久久丁香 | 欧美无乱码久久久免费午夜一区 | 日韩精品一区二区三区老鸭窝 | 久久久久久久久久久久91 | 黄色精品 | 国产精品高潮呻吟久久av野狼 | 欧美xxxⅹ性欧美大片 | 在线免费观看黄色 | 国产高清自拍视频在线观看 | 盗摄精品av一区二区三区 | 日本精品久久久一区二区三区 | 欧美一级在线观看 |