Android開發(fā)者在語言限制方面面臨著一個(gè)困境。眾所周知,目前的Android開發(fā)只支持Java 6(語言本身從Java 7開始進(jìn)行了一些改進(jìn)),因此我們每天只能使用一種古老的語言來進(jìn)行開發(fā),這極大地降低了我們的生產(chǎn)力,同時(shí)也迫使我們不得不編寫大量的樣板與脆弱的代碼,然而這樣的代碼是難以閱讀和維護(hù)的。幸運(yùn)的是,Android程序是運(yùn)行在Java虛擬機(jī)之上的,因此從技術(shù)上來說,可以運(yùn)行在JVM之上的一切都可用于開發(fā)Android應(yīng)用?,F(xiàn)在已經(jīng)有很多可以生成JVM能夠執(zhí)行的字節(jié)碼的語言,其中一些語言開始嶄露頭角并逐步流行起來,Kotlin就是其中的佼佼者。
何為Kotlin?
Kotlin是一門運(yùn)行在JVM之上的語言。它由Jetbrains創(chuàng)建,而Jetbrains則是諸多強(qiáng)大的工具(如知名的Java IDE IntelliJ IDEA)背后的公司。Kotlin是一門非常簡單的語言,其主要目標(biāo)之一就是提供強(qiáng)大語言的同時(shí)又保持簡單且精簡的語法。其主要特性如下所示:
輕量級(jí):這一點(diǎn)對(duì)于Android來說非常重要。項(xiàng)目所需要的庫應(yīng)該盡可能的小。Android對(duì)于方法數(shù)量有嚴(yán)格的限制,Kotlin只額外增加了大約6000個(gè)方法。
互操作:Kotlin可與Java語言無縫通信。這意味著我們可以在Kotlin代碼中使用任何已有的Java庫;因此,即便這門語言還很年輕,但卻已經(jīng)可以使用成百上千的庫了。除此之外,Kotlin代碼還可以為Java代碼所用,這意味著我們可以使用這兩種語言來構(gòu)建軟件。你可以使用Kotlin開發(fā)新特性,同時(shí)使用Java實(shí)現(xiàn)代碼基的其他部分。
強(qiáng)類型:我們很少需要在代碼中指定類型,因?yàn)榫幾g器可以在絕大多數(shù)情況下推斷出變量或是函數(shù)返回值的類型。這樣就能獲得兩個(gè)好處:簡潔與安全。
Null安全:Java最大的一個(gè)問題就是null。如果沒有對(duì)變量或是參數(shù)進(jìn)行null判斷,那么程序當(dāng)中就有可能拋出大量的NullPointerException,然而在編碼時(shí)這些又是難以檢測(cè)到的。Kotlin使用了顯式的null,這會(huì)強(qiáng)制我們?cè)诒匾獣r(shí)進(jìn)行null檢查。
目前Kotlin的版本是1.0.0 Beta 3,不過正式版很快就會(huì)發(fā)布。它完全可以用在生產(chǎn)當(dāng)中,現(xiàn)在就已經(jīng)有很多公司成功應(yīng)用上了Kotlin。
為何說Kotlin非常適合于Android?
基本上,這是因?yàn)镵otlin的所有特性都非常適合于Android生態(tài)圈。Kotlin的庫非常小,我們?cè)陂_發(fā)過程中不會(huì)引入額外的成本。其大小相當(dāng)于support-v4庫,我們?cè)诤芏囗?xiàng)目中所使用的庫都比Kotlin大。除此之外,Android Studio(官方的Android IDE)是基于IntelliJ構(gòu)建的。這意味著我們的IDE對(duì)該語言提供了非常棒的支持。我們可以很快就配置好項(xiàng)目,并且使用熟悉的IDE進(jìn)行開發(fā)。我們可以繼續(xù)使用Gradle以及IDE所提供的各種運(yùn)行與調(diào)試特性。這與使用Java開發(fā)應(yīng)用別無二致。歸功于互操作性,我們可以在Kotlin代碼中使用Android SDK而不會(huì)遇到任何問題。實(shí)際上,部分SDK使用起來會(huì)變得更加簡單,這是因?yàn)榛ゲ僮餍允欠浅?a href="http://ttokpm.com/v/" target="_blank">智能的,比如說它可以將getters與setters映射到Kotlin屬性上,我們也可以以閉包的形式編寫監(jiān)聽器。
如何在Android開發(fā)中使用Kotlin?
過程非常簡單,只需按照下面的步驟來即可:
從IDE plugins中下載Kotlin插件
在模塊中創(chuàng)建Kotlin類
使用“Configure Kotlin in Project…”
開始編碼
Kotlin的一些特性
Kotlin擁有大量非常打動(dòng)人心的特性,這里無法一一進(jìn)行介紹,不過我們來看一下其中最為重要的一些。
Null安全
如前所述,Kotlin是null安全的。如果一個(gè)類型可能為null,那么我們就需要在類型后面加上一個(gè)?。這樣,每次在使用該類型的變量時(shí),我們都需要進(jìn)行null檢查。比如說,如下代碼將無法編譯通過:
var artist: Artist? = null? artist.print()
第2行會(huì)顯示一個(gè)錯(cuò)誤,因?yàn)闆]有對(duì)變量進(jìn)行null檢查。我們可以這樣做:
if (artist != null) { ? artist.print()? }
這展示了Kotlin另一個(gè)出色的特性:智能類型轉(zhuǎn)換。如果檢查了變量的類型,那就無需在檢查作用域中對(duì)其進(jìn)行類型轉(zhuǎn)換。這樣,我們現(xiàn)在就可以在if中將artist作為Artist類型的變量了。這對(duì)于其他檢查也是適用的。還有一種更簡單的方式來檢查null,即在調(diào)用對(duì)象的函數(shù)前使用?。甚至還可以通過Elvis運(yùn)算符?提供另外一種做法:
val name = artist?.name ?: ""
數(shù)據(jù)類
在Java中,如果想要?jiǎng)?chuàng)建數(shù)據(jù)類或是POJO類(只保存了一些狀態(tài)的類),我們需要?jiǎng)?chuàng)建一個(gè)擁有大量字段、getters與setters的類,也許還要提供toString與equals方法:
public class Artist { private long id; private String name; private String url; private String mbid; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMbid() { return mbid; } public void setMbid(String mbid) { this.mbid = mbid; } @Override public String toString() { return "Artist{" + "id=" + id + ", name='" + name + ''' + ", url='" + url + ''' + ", mbid='" + mbid + ''' + '}'; } }
在Kotlin中,上述代碼可以寫成下面這樣:
data class Artist (? var id: Long, var name: String, var url: String, var mbid: String)
Kotlin使用屬性而非字段?;旧希瑢傩跃褪亲侄渭由掀鋑etter與setter。
互操作
Kotlin提供了一些非常棒的互操作特性,這對(duì)于Android開發(fā)幫助非常大。其中之一就是擁有單個(gè)方法的接口與lambda表達(dá)式之間的映射。這樣,下面這個(gè)單擊監(jiān)聽器:
view.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View) { toast("Click")? } ?})
可以寫成這樣:
view.setOnClickListener { toast("Click") }
此外,getters與setters都會(huì)自動(dòng)映射到屬性上。這并不會(huì)造成性能上的損失,因?yàn)樽止?jié)碼實(shí)際上只是調(diào)用原來的getters與setters。如下代碼所示:
supportActionBar.title = title textView.text = title contactsList.adapter = ContactsAdapter()
Lambda表達(dá)式
Lambda表達(dá)式會(huì)在極大程度上精簡代碼,不過重要的是借助于Lambda表達(dá)式,我們可以做到之前無法實(shí)現(xiàn)或是實(shí)現(xiàn)起來非常麻煩的事情。借助于Lambda表達(dá)式,我們可以以一種更加函數(shù)式的方式來思考問題。Lambda表達(dá)式其實(shí)就是一種指定類型,并且該類型定義了一個(gè)函數(shù)的方式。比如說,我們可以像下面這樣定義一個(gè)變量:
val listener: (View) -> Boolean
該變量可以聲明一個(gè)函數(shù),它接收一個(gè)view并返回這個(gè)函數(shù)。我們需要通過閉包的方式來定義函數(shù)的行為:
val listener = { view: View -> view is TextView }
上面這個(gè)函數(shù)會(huì)接收一個(gè)View,如果該view是TextView的實(shí)例,那么它就會(huì)返回true。由于編譯器可以推斷出類型,因此我們無需指定。還可以更加明確一些:
val listener: (View) -> Boolean = { view -> view is TextView }
借助于Lambda表達(dá)式,我們可以拋棄回調(diào)接口的使用。只需設(shè)置希望后面會(huì)被調(diào)用的函數(shù)即可:
fun asyncOperation(value: Int, callback: (Boolean) -> Unit) { ... callback(true)? } asyncOperation(5) { result -> println("result: $result") }
還有一種更加簡潔的方式,如果函數(shù)只接收一個(gè)參數(shù),那就可以使用保留字it:
asyncOperation(5) { println("result: $it") }
Anko
Anko是Kotlin團(tuán)隊(duì)開發(fā)的一個(gè)庫,旨在簡化Android開發(fā)。其主要目標(biāo)在于提供一個(gè)DSL,使用Kotlin代碼來聲明視圖:
verticalLayout { val name = editText() button("Say Hello") { onClick { toast("Hello, ${name.text}!") } } }
它還提供了其他一些很有用的特性。比如說,導(dǎo)航到其他Activity:
startActivity("id" to res.id, "name" to res.name)
總結(jié)
如你所見,Kotlin在很多方面都簡化了Android的開發(fā)工作。它會(huì)提升你的生產(chǎn)力,并且可以通過非常不同且更加簡單的方式來解決一些常見的問題。
?
評(píng)論
查看更多