微信團隊分享:Kotlin漸被認可,Android版微信的技術嚐鮮之旅1、引言2、概述3、“烹飪”準備4、“烹飪”過程5、開鍋,上菜6、如何更好地瞭解Kotlin這種食材的味道附錄:QQ、微信團隊原創

本文由微信開發團隊工程是由“oneliang”原創發表於WeMobileDev公衆號,內容稍有改動。

1、引言

Kotlin 是一個用於現代多平臺應用的靜態編程語言,由 JetBrains 開發(也就是開發了號稱Java界最智能的集成開發工具IntelliJ IDEA的公司)。Kotlin可以編譯成Java字節碼(就像Groovy和Scala一樣),也可以編譯成JavaScript,方便在沒有JVM的設備上運行。Kotlin已於2017年的Google I/O開發者大會上正式被宣佈爲Android官方支持開發語言(見《[資訊] Kotlin成爲Android官方開發語言!》)。

有人說Kolin對於Android的作用,是不是Swift對於iOS的作用一樣(主要用於降低Objective-C開發門檻等)。實際上,Kotlin對於Android的意義和重要性要遠大於Swift對於iOS,因爲不管是Objective-C還是Swift,它們至少都是蘋果自已的東西,而悲劇的是Java並不屬於Google。鑑於Google和Oracle(Java的創造者SUN公司早就被Oracle收購了)的官司(見《[資訊] Java侵權案逆轉:Google需賠88億!》),如何解決掉Java這個如鯁在喉的歷史遺留,是Android決策者早就在考慮的問題,只是恰好選中了Kotlin而已。

Google官方已在各種場合直接或間接地表明瞭對於Kotlin和Java的態度——那就是Kotlin是 “Over” Java的(即可以理解爲Kotlin在ANdroid中的定位是高於Java的)。所以,不管Android開發者有沒有做好準備,或者還在糾結要不要學習Kotlin時,都不影響Kotlin在Android中的定位和越來越明確的地位。但無論如何,對於Android開發者來說,多學一門技術確實很痛苦,但提前做好準備是更明智之選,至少到了Kotlin真的取代Java的那一天,而不至於後懂準備地太晚。

作爲移動端即時通訊IM應用的王者——微信,爲了始終保持技術的領先性,無論日後Kotlin在微信客戶中的重要性幾何,技術團隊做好技術儲備和預研實踐是肯定有必要的,於是便有了本文的整理和分享,希望業界共同學習、互相交流。

2、概述

微信訂閱號助手的Android App項目首次嘗試使用Kotlin進行大規模的業務開發(483個Kt文件,3.8W行不包含空行的Kt代碼),一開始接觸Kotlin的時候難免會有點不適應,但經過幾天的強制使用後,慢慢有些感覺,項目落地後回顧了一下,發現Kotlin確實是有它獨特的風味。

什麼是微信訂閱號助手?

微信公衆平臺“訂閱號助手”APP已正式上架App Store,通過這款訂閱號助手APP,公衆號運營者可以快捷地編輯和發表內容、方便地處理留言和回覆粉絲消息。 訂閱號助手app能將你的iPhone變成一個隨身的公衆號“工作室”,無論身處何地,你都可以發表內容、與讀者互動。訂閱號助手app簡潔的編輯工具讓每個人輕鬆變身爲作者,留住即刻的靈感,盡享內容創作的樂趣。訂閱號助手app讓每個有才華的個體都有機會被關注,都有自己的品牌。

3、“烹飪”準備

食材:

1)Android,主要食材(指Framework、Api等);

2)Kotlin,食用安全、味鮮(擴展函數)、香(重載)、甜(富含糖份Lambda),第二主要食材,切好塊狀;

3)Java,少量,Kotlin這種食材需要它來做引子。

鍋:

AndroidStudio、Eclipse這兩個牌子的鍋質量都不錯。

調味料:

Kotlin Android Extension、Android KTX、AndroidX、Anko等。

如果沒有上述這些材料請移步到如下網址"購買":

https://developers.google.com/android

https://kotlinlang.org/docs/reference

https://www.oracle.com/java

4、“烹飪”過程

1)開火,放少量食用油;

2)先把Android倒進去,伴兩下;

3)倒少量Java,主要是"字節碼"和"工具部分",再伴兩下;

4)把切好塊的Kotlin一塊塊慢慢平鋪在Android上面,把Android蓋住;

5)慢火煮3-5分鐘,觀察一下這個過程:

Kotlin把Android的味道慢慢釋放出來,比Android + Java更香; Kotlin與Java融爲一體 (前提是少量Java,如果Java放得太多,香味會受影響,粘合不夠好,容易鬆散(NPE));

6)關火,燜一會。

5、開鍋,上菜

色香味倶全,敬請盡情享受這番獨特的風味。

5.1 特色風味一:食用安全

食用安全,Nullable or NotNul從源頭抓起。

Kotlin代碼安全性更強:

varoutput: String output = null// Compilation error val name: String? = null// Nullable type println(name.length())      // Compilation error

食用安全從從源頭上抓起,只要跟定義不符就編譯不通過,這是Kotlin小而精的一個優點,一下子能把整碟"菜"的安全係數提高,此Code來自官方文檔。

5.2 特色風味二:鮮

擴展函數,味道鮮美,百吃不厭。

項目工具類的另一種寫法:

fun String.toIntSafely(defaultValue: Int = 0): Int {     returntry{         this.toInt()     } catch(e: Exception) {         defaultValue     } } fun main(args: Array<String>) {     println("1".toIntSafely()) }

String 轉 Int,這種需求幾乎很多項目都是需要,像上述Kotlin如果是在Java裏面描述的話,估計會寫成這樣:

public final class StringUtil{     private StringUtil() {}     public static int stringToInt(String string, int defaultValue) {         //省略     } }

使用時:

StringUtil.stringToInt("1", 0);

大家看到這裏可能會覺得沒什麼,大家都是工具類,用的時候有些小差別而已。

但正因爲這些小差別,優點就體現出來了,確實是鮮美:

1)不需要記住工具類的名字和方法的名字:假如你是一個剛接手項目的新人,正準備做一個需求開發,突然需要這種String to Int的工具,但是不知道工具在哪,這就好比你去到一個陌生人的家裏,想找個螺絲刀擰個鬆掉的螺絲一樣,這“螺絲刀”在哪?除了問“主人”之外,要麼就是“翻櫃子”,這不就顯得效率低麼?使用Kotlin的擴展函數就能有效避免前面所說的問題,接手項目的新人只需要輕輕的“.”一下,滾兩下鼠標,"toIntSafely"的方法就會看到。這就爲什麼你看Kotlin的Java擴展庫很多都是通過擴展函數來封裝;

2)方法的類歸屬更好理解:以上述的"toIntSafely"爲例,String.toIntSafely,使得開發者更容易直觀感受到這個函數是用於String,不像StringUtil.stringToInt沒有歸屬可言,純粹就是一個工具函數,不如Kotlin的寫法容易理解;

3)對定義函數者的要求高了:正因體現了函數的類歸屬,也就使得開發者在定義函數的時候需要考慮歸屬給哪個類還是頂層函數這些問題,歸屬的範圍少了,會導致不好用,範圍廣了又怕暴露導致濫用或者誤用。

5.3 特色風味三:香

重載(Overload),回味無窮。

雖然這個概念在面向對象領域用得很多,但Kotlin這個重載的味道真是令我們吃上癮。

重載在工具類的場景用得非常多,一個項目下來沒工具類也是不可能。

例如我們在項目中會封裝一些對話框(Dialog)工具類供開發的同學一句調用:

1)開發的同學需要在界面顯示一個Dialog,只想改變Dialog的內容,那麼Java裏面就有showDialog(String message)的寫法;

2)開發的同學需要在界面顯示一個Dialog,即想改變Dialog的標題,又想改變Dialog的內容,那麼Java裏面就有showDialog(String title, String message)的寫法;

3)開發的同學想改變Dialog裏面Icon的....

4)開發的同學想......

這些場景估計做Android開發的同學都會碰到,其實不限於Android,Java開發的同學也經常遇到。

我們看看Kotlin是怎樣把這些需求收攏:

fun showDialog(title: String = "標題", message: String = "內容") {     //TODO }

這個寫法一下子滿足 2的2次方(4) 種重載方法:

showDialog() showDialog("新標題") showDialog(message = "新內容") showDialog("新標題", "新內容")

這種重載方式有效地減少我們項目中的重載方法數量,使得我們項目開發更簡潔和更有效率 ,自然就回味無窮。

5.4 特色風味四:甜而不膩

帶了糖,甜而不膩。

Kotlin裏面Function與Lambda既可相互理解,又有其味道(寫法)上的一些差異。

味道 (結果) 一樣,但味道消去的過程 (用法) 有差別。

Function(函數)常用寫法:

fun f(x: Int): Any {     returnAny() }

用法:

val y = f(1)

Function(函數)的一種Lambda寫法:

fun f() = { x: Int -> Any() } 等價於 fun f(): (Int) -> Any = { x: Int -> Any() }

用法:

val y = f()(1) 或 val y = f().invoke(1)

Lambda寫法:

val f = { x: Int -> Any() } 等價於 val f: (Int) -> Any = { x: Int -> Any }

用法:

val y = f(1) 或 val y = f.invoke(1)

細節點:Function時,有"="跟沒有"="意義不一樣,有"="的時候可以理解右邊( { x: Int -> Any() } )是 左邊函數返回類型((Int) -> Any) 的實現。

函數不用置疑,項目裏面必備。

Lambda:

Lambda,語法糖,這是怎樣的一種成份?

Lambda是長這樣的:

val block: () -> Unit = {} val sum: (Int, Int) -> Int = { p1, p2 -> p1 + p2 }

Lambda令我們的項目減少了很多接口類,尤其是回調接口,我們項目幾乎沒有。一般的業務場景裏面回調接口都會用得不少,Lambda能有效減少這種Callback接口的定義,少寫不少接口類,事半功倍。

另lambda裏面不能寫return,最後一行的值就是返回值。

從數學函數角度抽象理解:

函數: y = f(x)

〉假設x與y都是Int類型

可以理解爲 Kotlin 函數:

fun f(x: Int): Int {     return1 // 這裏的返回值就是對應y }

也可以理解爲 Lambda:

val f = { x: Int -> 1 } 等價於 val f: (Int) -> Int = { x: Int -> 1 }

使用時f(1),但是如果像上述那種f(x)的kotlin函數與f(x)的lambda同時同名同方法簽名存在,使用上要f(1)與f.invoke(1)來區分是函數調用還是lambda調用。

〉假設x與y都是Lambda類型

x是Lambda類型 (Int) -> Int ,y是Lambda類型 (Int) -> Int,可以換算成:

fun f(x: (Int) -> Int): (Int) -> Int {     return{ it -> x(it) } }

或這樣:

fun f(x: (Int) -> Int): (Int) -> Int = { it -> x(it) }

使用時:

f { it -> it + 10 }(1) or f { it -> it + 10 }.invoke(1)

或 Lambda:

val f: ((Int) -> Int) -> ((Int) -> Int) = { x -> { it -> x(it) } } // val時要inline

使用時:

f.invoke { it -> it + 10 }.invoke(1)

通過上述的 替換 能更好地理解和使用Lambda。

6、如何更好地瞭解Kotlin這種食材的味道

Kotlin用於Java領域,中間產物毫無疑問還是字節碼,因此本質還是Java的基礎知識,反編譯Kotlin生成的字節碼是學習Kotlin一種較好的方式,可利用AndroidStudio的Tools來反編譯kt,能幫助快速理解Kotlin。

謝謝品嚐這份美味,希望Kotlin這款食材能帶給各位讀者不少Android上的特色的風味。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章