Android Kotlin的使用及簡(jiǎn)單實(shí)例
Android Kotlin的使用及簡(jiǎn)單實(shí)例
寫(xiě)在前面的話,作為一個(gè)不熬夜的人,一覺(jué)醒來(lái)發(fā)現(xiàn)Kotlin成為了Android的官方語(yǔ)言,可謂是大喜過(guò)望。為了趁熱打鐵,我決定提前三天放出原定本周日Release的文章。希望能及時(shí)讓大家了解一下Kotlin。
相信很多開(kāi)發(fā)人員,尤其是Android開(kāi)發(fā)者都會(huì)或多或少聽(tīng)說(shuō)過(guò)Kotlin,當(dāng)然如果沒(méi)有聽(tīng)過(guò)或者不熟悉也沒(méi)有關(guān)系。因?yàn)楸酒恼乱约安┛秃笃诘膬?nèi)容會(huì)涉及到很多關(guān)于Kotlin的知識(shí)分享。
在寫(xiě)這篇文章前的一個(gè)多月,F(xiàn)lipboard中國(guó)的Android項(xiàng)目確定了正式將Kotlin作為項(xiàng)目開(kāi)發(fā)語(yǔ)言,這就意味著新增的代碼文件將以Kotlin代碼格式出現(xiàn),而且同時(shí)舊的Java代碼也將會(huì)陸陸續(xù)續(xù)翻譯成Kotlin代碼。在使用Kotlin的這段時(shí)間,被它的簡(jiǎn)潔,高效,快捷等等特點(diǎn)震撼,所以有必要寫(xiě)一篇文章來(lái)談一談Kotlin的特性,如若能取得推廣Kotlin的效果則倍感欣慰。
Kotlin的“簡(jiǎn)歷”
- 來(lái)自于著名的IDE IntelliJ IDEA(Android Studio基于此開(kāi)發(fā)) 軟件開(kāi)發(fā)公司 JetBrains(位于東歐捷克)
- 起源來(lái)自JetBrains的圣彼得堡團(tuán)隊(duì),名稱(chēng)取自圣彼得堡附近的一個(gè)小島(Kotlin Island)
- 一種基于JVM的靜態(tài)類(lèi)型編程語(yǔ)言
來(lái)自知名的工具開(kāi)發(fā)商JetBrains,也就決定了Kotlin的基因中必然包含實(shí)用與高效等特征。那我們接下來(lái)看一看Kotlin的特點(diǎn),當(dāng)然這也是我改用Kotlin的重要原因。
語(yǔ)法簡(jiǎn)單,不啰嗦
//variables and constants
var currentVersionCode = 1 //變量當(dāng)前的版本號(hào),類(lèi)型Int可以根據(jù)值推斷出來(lái)
var currentVersionName : String = "1.0" //顯式標(biāo)明類(lèi)型
val APPNAME = "droidyue.com" //常量APPNAME 類(lèi)型(String)可以根據(jù)值推斷出來(lái)
//methods
fun main(args: Array<String>) {
println(args)
}
// class
class MainActivity : AppCompatActivity() {
}
// data class 自動(dòng)生成getter,setting,hashcode和equals等方法
data class Book(var name: String, val price: Float, var author: String)
//支持默認(rèn)參數(shù)值,減少方法重載
fun Context.showToast(message: String, duration:Int = Toast.LENGTH_LONG) {
Toast.makeText(this, message, duration).show()
}
- Kotlin支持類(lèi)型推斷,沒(méi)有Java那樣的啰嗦。
- 另外用var表示變量,val表示常量更加的簡(jiǎn)潔
- 方法也很簡(jiǎn)單,連function都縮寫(xiě)成了fun,平添了幾分雙關(guān)之意。
- 類(lèi)的繼承和實(shí)現(xiàn)很簡(jiǎn)單,使用:即可
- Kotlin每個(gè)句子都不需要加分號(hào)(;)
空指針安全
空指針(NullPointerException或NPE)是我們使用Java開(kāi)發(fā)程序中最常見(jiàn)的崩潰了。因?yàn)樵贘ava中我們不得不寫(xiě)很多防御性的代碼,比如這樣
public void test(String string) {
if (string != null) {
char[] chars = string.toCharArray();
if (chars.length > 10) {
System.out.println(((Character)chars[10]).hashCode());
}
}
}
在Kotlin中空指針異常得到了很好的解決。
1.在類(lèi)型上的處理,即在類(lèi)型后面加上?,即表示這個(gè)變量或參數(shù)以及返回值可以為null,否則不允許為變量參數(shù)賦值為null或者返回null
2.對(duì)于一個(gè)可能是null的變量或者參數(shù),在調(diào)用對(duì)象方法或者屬性之前,需要加上?,否則編譯無(wú)法通過(guò)。
如下面的代碼就是Kotlin實(shí)現(xiàn)空指針安全的一個(gè)例子,而且相對(duì)Java實(shí)現(xiàn)而言,簡(jiǎn)直是一行代碼搞定的。
fun testNullSafeOperator(string: String?) {
System.out.println(string?.toCharArray()?.getOrNull(10)?.hashCode())
}
testNullSafeOperator(null)
testNullSafeOperator("12345678901")
testNullSafeOperator("123")
//result
null
49
null
關(guān)于空指針安全的原理,可以參考這篇文章研究學(xué)習(xí)Kotlin的一些方法
支持方法擴(kuò)展
很多時(shí)候,F(xiàn)ramework提供給我們的API往往都時(shí)比較原子的,調(diào)用時(shí)需要我們進(jìn)行組合處理,因?yàn)榫蜁?huì)產(chǎn)生了一些Util類(lèi),一個(gè)簡(jiǎn)單的例子,我們想要更快捷的展示Toast信息,在Java中我們可以這樣做。
public static void longToast(Context context, String message) {
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
但是Kotlin的實(shí)現(xiàn)卻讓人驚奇,我們只需要重寫(xiě)擴(kuò)展方法就可以了,比如這個(gè)longToast方法擴(kuò)展到所有的Context對(duì)象中,如果不去追根溯源,可能無(wú)法區(qū)分是Framework提供的還是自行擴(kuò)展的。
fun Context.longToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
applicationContext.longToast("hello world")
注意:Kotlin的方法擴(kuò)展并不是真正修改了對(duì)應(yīng)的類(lèi)文件,而是在編譯器和IDE方面做得處理。使我們看起來(lái)像是擴(kuò)展了方法。
Lambda, 高階函數(shù),Streams API, 函數(shù)式編程支持
所謂的Lambda表達(dá)式是匿名函數(shù),這使得我們的代碼會(huì)更加的簡(jiǎn)單。比如下面的代碼就是lambda的應(yīng)用。
findViewById(R.id.content).setOnClickListener {
Log.d("MainActivity", "$it was clicked")
}
所謂的高階函數(shù)就是
- 可以接受函數(shù)作為參數(shù)
- 也可以返回函數(shù)作為結(jié)果
舉一個(gè)接受函數(shù)作為參數(shù)的例子。在Android開(kāi)發(fā)中,我們經(jīng)常使用SharedPreference來(lái)存儲(chǔ)數(shù)據(jù),如果忘記調(diào)用apply或者commit則數(shù)據(jù)修改不能應(yīng)用。利用Kotlin中的高階函數(shù)的功能,我們能更好的解決這個(gè)問(wèn)題
fun SharedPreferences.editor(f: (SharedPreferences.Editor) -> Unit) {
val editor = edit()
f(editor)
editor.apply()
}
//實(shí)際調(diào)用
PreferenceManager.getDefaultSharedPreferences(this).editor {
it.putBoolean("installed", true)
}
當(dāng)然這上面的例子中我們也同時(shí)使用了方法擴(kuò)展這個(gè)特性。
Kotlin支持了Streams API和方法引用,這樣函數(shù)式編程更加方便。比如下面的代碼就是我們結(jié)合Jsoup,來(lái)抓取某個(gè)proxy網(wǎng)站的數(shù)據(jù),代碼更加簡(jiǎn)單,實(shí)現(xiàn)起來(lái)也快速。
fun parse(url: String): Unit {
Jsoup.parse(URL(url), PARSE_URL_TIMEOUT).getElementsByClass("table table-sm")
.first().children()
.filter { "tbody".equals(it.tagName().toLowerCase()) }
.flatMap(Element::children).forEach {
trElement ->
ProxyItem().apply {
trElement.children().forEachIndexed { index, element ->
when (index) {
0 -> {
host = element.text().split(":")[0]
port = element.text().split(":")[1].toInt()
}
1 -> protocol = element.text()
5 -> country = element.text()
}
}
}.let(::println)
}
}
字符串模板
無(wú)論是Java還是Android開(kāi)發(fā),我們都會(huì)用到字符串拼接,比如進(jìn)行日志輸出等等。在Kotlin中,字符串模板是支持的,我們可以很輕松的完成一個(gè)字符串?dāng)?shù)組的組成
val book = Book("Thinking In Java", 59.0f, "Unknown")
val extraValue = "extra"
Log.d("MainActivity", "book.name = ${book.name}; book.price=${book.price};extraValue=$extraValue")
注意:關(guān)于字符串拼接可以參考這篇文章Java細(xì)節(jié):字符串的拼接
與Java交互性好
Kotlin和Java都屬于基于JVM的編程語(yǔ)言。Kotlin和Java的交互性很好,可以說(shuō)是無(wú)縫連接。這表現(xiàn)在
- Kotlin可以自由的引用Java的代碼,反之亦然。
- Kotlin可以現(xiàn)有的全部的Java框架和庫(kù)
- Java文件可以很輕松的借助IntelliJ的插件轉(zhuǎn)成kotlin
Kotlin應(yīng)用廣泛
Kotlin對(duì)Android應(yīng)用開(kāi)發(fā)支持廣泛,諸多工具,比如kotterknife(ButterKnife Kotlin版),RxKotlin,Anko等等,當(dāng)然還有已經(jīng)存在的很多Java的庫(kù)都是可以使用的。
除此之外,Kotlin也可以編譯成JavaScript。最近使用Kotlin寫(xiě)了一段抓取proxy的代碼,實(shí)現(xiàn)起來(lái)非??旖荨I踔帘燃僇avaScript實(shí)現(xiàn)起來(lái)要快很多。
fun handle(): Unit {
window.onload = {
document.getElementsByClassName("table table-sm").asList().first()
.children.asList().filter { "TBODY".equals(it.tagName.toUpperCase()) }
.flatMap { it.children.asList() }.forEach {
var proxyItem = ProxyItem()
it.children.asList().forEachIndexed { index, element ->
when (index) {
0 -> {
proxyItem.host = element.trimedTextContent()?.split(":")?.get(0) ?: ""
proxyItem.port = element.trimedTextContent()?.split(":")?.get(1)?.trim()?.toInt() ?: -1
}
1 -> proxyItem.protocol = element.trimedTextContent() ?: ""
5 -> proxyItem.country = element.trimedTextContent() ?: ""
}
}.run {
console.info("proxyItem $proxyItem")
}
}
}
}
關(guān)于性能
Kotlin的執(zhí)行效率和Java代碼的執(zhí)行效率理論上一致的。有時(shí)候Kotlin可能會(huì)顯得高一些,比如Kotlin提供了方法的inline設(shè)置,可以設(shè)置某些高頻方法進(jìn)行inline操作,減少了運(yùn)行時(shí)的進(jìn)棧出棧和保存狀態(tài)的開(kāi)銷(xiāo)。
讀到這里,是不是想要嘗試一下Kotlin呢,它簡(jiǎn)潔的語(yǔ)法,匯集諸多特性,高效率實(shí)現(xiàn)等等,已經(jīng)在國(guó)外風(fēng)生水起,國(guó)外的Pintereset, Square, Flipboard等公司已經(jīng)開(kāi)始應(yīng)用到生產(chǎn)中。
關(guān)于轉(zhuǎn)向Kotlin
其實(shí),我在做決定之前(當(dāng)時(shí)Kotlin還沒(méi)有被欽定)也曾有過(guò)考慮,是不是選擇了Kotlin就意味著放棄Java呢,冷靜下來(lái)想一想,其實(shí)并不是那么回事,因?yàn)镵otlin與Java語(yǔ)法太相近,以及在Kotlin中無(wú)時(shí)無(wú)刻不在和Java相關(guān)的東西打交道,所以這點(diǎn)顧慮不是問(wèn)題的。
對(duì)于個(gè)人的項(xiàng)目來(lái)轉(zhuǎn)向Kotlin,通常不是很難的選擇,畢竟Kotlin是那么優(yōu)秀的語(yǔ)言,相信很多人還是愿意嘗試并使用這個(gè)事半功倍的語(yǔ)言的。
而比較難抉擇的情況是如果如何讓團(tuán)隊(duì)轉(zhuǎn)用Kotlin,個(gè)人認(rèn)為團(tuán)隊(duì)難以轉(zhuǎn)用的原因有很多,比如學(xué)習(xí)成本,歷史包袱等等。但其實(shí)根本原因還是思維方式的問(wèn)題,歪果仁喜歡用工具來(lái)提升開(kāi)發(fā)效率,因?yàn)槿肆Τ杀竞芨?。而?guó)內(nèi)團(tuán)隊(duì)提高效率的辦法通常是增加成員。好在Flipboard 美國(guó)團(tuán)隊(duì)自2015年(可能更早)就引入了Kotlin,因此中國(guó)團(tuán)隊(duì)這邊選用Kotlin也更加順?biāo)浦邸.?dāng)然更主要的是目前團(tuán)隊(duì)規(guī)模不大,成員一致認(rèn)可Kotlin的優(yōu)點(diǎn)。
關(guān)于團(tuán)隊(duì)轉(zhuǎn)用Kotlin的方法,一般比較行得通的辦法是自上而下的推行。這就意味著要么直接的技術(shù)負(fù)責(zé)人比較開(kāi)明要么就是需要有人來(lái)不斷推介來(lái)影響團(tuán)隊(duì)。
做個(gè)比較現(xiàn)實(shí)的比擬,Java就像是一趟從我的家鄉(xiāng)保定開(kāi)往北京西的耗時(shí)將近2個(gè)小時(shí)甚至更長(zhǎng)的普通列車(chē),而Kotlin則是那趟僅需40分鐘就能到達(dá)的高鐵。通常的人都會(huì)選擇高鐵,因?yàn)樗?jié)省了時(shí)間和提高了體驗(yàn)。這個(gè)時(shí)間和體驗(yàn)對(duì)應(yīng)編程中的,我想應(yīng)該是高效率和高可讀性,可維護(hù)性的代碼。
現(xiàn)在好了,有了Google的支持,Kotlin轉(zhuǎn)Android相信在不久的將來(lái)就會(huì)全面展開(kāi)。篡改Python的一句名言“人生苦短,我用Kotlin”,這樣一個(gè)高效實(shí)用的語(yǔ)言應(yīng)該會(huì)被越來(lái)越多的團(tuán)隊(duì)所接受,并應(yīng)用到開(kāi)發(fā)生產(chǎn)中。當(dāng)然也希望在國(guó)內(nèi)環(huán)境下大放異彩。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Android ListView實(shí)現(xiàn)簡(jiǎn)單列表功能
這篇文章主要為大家詳細(xì)介紹了Android ListView實(shí)現(xiàn)簡(jiǎn)單列表功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
解決android有的手機(jī)拍照后上傳圖片被旋轉(zhuǎn)的問(wèn)題
這篇文章主要介紹了解決android有的手機(jī)拍照后上傳圖片被旋轉(zhuǎn)的問(wèn)題的相關(guān)資料,需要的朋友可以參考下2016-09-09
Android RecyclerView仿新聞?lì)^條的頻道管理功能
這篇文章主要介紹了Android RecyclerView仿新聞?lì)^條的頻道管理功能,需要的朋友可以參考下2017-06-06
Android 中啟動(dòng)自己另一個(gè)程序的activity如何實(shí)現(xiàn)
這篇文章主要介紹了Android 中啟動(dòng)自己另一個(gè)程序的activity如何實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-04-04
Android實(shí)現(xiàn)長(zhǎng)圖展開(kāi)與收起效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)長(zhǎng)圖展開(kāi)與收起效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09
Android RecyclerView 數(shù)據(jù)綁定實(shí)例代碼
本文主要介紹Android RecyclerView 數(shù)據(jù)綁定的資料,這里詳細(xì)說(shuō)明如何實(shí)現(xiàn) Android RecyclerView的數(shù)據(jù)綁定,并附示例代碼,有需要的小伙伴可以參考下2016-09-09
Jetpack Compose實(shí)現(xiàn)對(duì)話框和進(jìn)度條實(shí)例解析
對(duì)話框和進(jìn)度條其實(shí)并無(wú)多大聯(lián)系,放在一起寫(xiě)是因?yàn)閮烧叩膬?nèi)容都不多,所以湊到一起,對(duì)話框是我們平時(shí)開(kāi)發(fā)使用得比較多的組件,進(jìn)度條的使用頻率也很高,比如下載文件,上傳文件,處理任務(wù)時(shí)都可以使用進(jìn)度條2023-04-04
Android通過(guò)Handler與AsyncTask兩種方式動(dòng)態(tài)更新ListView(附源碼)
這篇文章主要介紹了Android通過(guò)Handler與AsyncTask兩種方式動(dòng)態(tài)更新ListView的方法,結(jié)合實(shí)例形式分析了ListView動(dòng)態(tài)更新的常用技巧,并附上完整實(shí)例源碼供讀者下載,需要的朋友可以參考下2015-12-12

