微信團隊分享:Kotlin漸被認可,Android版微信的技術嚐鮮之旅
本文由微信開發團隊工程是由“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收購了)的官司(見《
Google官方已在各種場合直接或間接地表明瞭對於Kotlin和Java的態度——那就是Kotlin是 “Over” Java的(即可以理解為Kotlin在ANdroid中的定位是高於Java的)。所以,不管Android開發者有沒有做好準備,或者還在糾結要不要學習Kotlin時,都不影響Kotlin在Android中的定位和越來越明確的地位。但無論如何,對於Android開發者來說,多學一門技術確實很痛苦,但提前做好準備是更明智之選,至少到了Kotlin真的取代Java的那一天,而不至於後懂準備地太晚。
作為移動端即時通訊IM應用的王者——微信,為了始終保持技術的領先性,無論日後Kotlin在微信客戶中的重要性幾何,技術團隊做好技術儲備和預研實踐是肯定有必要的,於是便有了本文的整理和分享,希望業界共同學習、互相交流。
(本文同步釋出於:http://www.52im.net/thread-2066-1-1.html)
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
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上的特色的風味。
附錄:QQ、微信團隊原創技術文章
《騰訊技術分享:騰訊是如何大幅降低頻寬和網路流量的(圖片壓縮篇)》
《騰訊技術分享:騰訊是如何大幅降低頻寬和網路流量的(音視訊技術篇)》
《騰訊技術分享:Android版手機QQ的快取監控與優化實踐》
《微信團隊分享:iOS版微信的高效能通用key-value元件技術實踐》
《微信團隊分享:iOS版微信是如何防止特殊字元導致的炸群、APP崩潰的?》
《騰訊技術分享:Android手Q的執行緒死鎖監控系統技術實踐》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(上篇)》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(下篇)》
《騰訊團隊分享 :一次手Q聊天介面中圖片顯示bug的追蹤過程分享》
《微信團隊分享:微信Android版小視訊編碼填過的那些坑》
《微信團隊披露:微信介面卡死超級bug“15。。。。”的來龍去脈》
《月活8.89億的超級IM微信是如何進行Android端相容測試的》
《微信客戶端團隊負責人技術訪談:如何著手客戶端效能監控和優化》
《微信團隊原創分享:Android版微信的臃腫之困與模組化實踐之路》
《微信團隊原創分享:微信客戶端SQLite資料庫損壞修復實踐》
《騰訊原創分享(一):如何大幅提升行動網路下手機QQ的圖片傳輸速度和成功率》
《騰訊原創分享(二):如何大幅壓縮行動網路下APP的流量消耗(下篇)》
《騰訊原創分享(三):如何大幅壓縮行動網路下APP的流量消耗(上篇)》
《如約而至:微信自用的移動端IM網路層跨平臺元件庫Mars已正式開源》
《開源libco庫:單機千萬連線、支撐微信8億使用者的後臺框架基石 [原始碼下載]》
《微信新一代通訊安全解決方案:基於TLS1.3的MMTLS詳解》
《微信團隊原創分享:Android版微信後臺保活實戰分享(程序保活篇)》
《微信團隊原創分享:Android版微信後臺保活實戰分享(網路保活篇)》
《Android版微信從300KB到30MB的技術演進(PPT講稿) [附件下載]》
《微信團隊原創分享:Android版微信從300KB到30MB的技術演進》
《微信技術總監談架構:微信之道——大道至簡(PPT講稿) [附件下載]》
《微信海量使用者背後的後臺系統儲存架構(視訊+PPT) [附件下載]》
《微信非同步化改造實踐:8億月活、單機千萬連線背後的後臺解決方案》
《架構之道:3個程式設計師成就微信朋友圈日均10億釋出量[有視訊]》
《微信團隊原創分享:Android記憶體洩漏監控和優化技巧總結》
《微信團隊原創Android資源混淆工具:AndResGuard [有原始碼]》
《移動端IM實踐:Android版微信如何大幅提升互動效能(一)》
《移動端IM實踐:Android版微信如何大幅提升互動效能(二)》
《移動端IM實踐:WhatsApp、Line、微信的心跳策略分析》
《移動端IM實踐:谷歌訊息推送服務(GCM)研究(來自微信)》
《信鴿團隊原創:一起走過 iOS10 上訊息推送(APNS)的坑》
《騰訊TEG團隊原創:基於MySQL的分散式資料庫TDSQL十年鍛造經驗分享》
《微信多媒體團隊訪談:音視訊開發的學習、微信的音視訊技術和挑戰等》
《瞭解iOS訊息推送一文就夠:史上最全iOS Push技術詳解》
《騰訊資深架構師乾貨總結:一文讀懂大型分散式系統設計的方方面面》
《騰訊音視訊實驗室:使用AI黑科技實現超低位元速率的高清實時視訊聊天》
《騰訊技術分享:微信小程式音視訊與WebRTC互通的技術思路和實踐》
《手把手教你讀取Android版微信和手Q的聊天記錄(僅作技術研究學習)》
《微信技術分享:微信的海量IM聊天訊息序列號生成實踐(演算法原理篇)》
《微信技術分享:微信的海量IM聊天訊息序列號生成實踐(容災方案篇)》
《騰訊技術分享:GIF動圖技術詳解及手機QQ動態表情壓縮技術實踐》
《微信團隊分享:Kotlin漸被認可,Android版微信的技術嚐鮮之旅》
>> 更多同類文章 ……
(本文同步釋出於:http://www.52im.net/thread-2066-1-1.html)