一周前開始學(xué)習(xí)kotlin,現(xiàn)在已經(jīng)在項(xiàng)目中開發(fā)使用了。我目前負(fù)責(zé)的項(xiàng)目老代碼非常多,之前的java代碼已經(jīng)有十多萬(wàn)行了。所以即便使用了kotlin,也只是在新建文件的代碼里使用,老代碼繼續(xù)用java。kotlin的好處就是完全兼容java,java調(diào)用kotlin,kotlin基本上無(wú)阻礙。
先說(shuō)說(shuō)為什么要轉(zhuǎn)kotlin
Google已經(jīng)明確kotlin為第一官方語(yǔ)言。我相信Google的決意,就像當(dāng)初毫不猶豫的拋棄eclipse轉(zhuǎn)向as。kotlin已經(jīng)是不可避免的大勢(shì)所趨了。
Kotlin與java代碼完全兼容。使用kotlin就好像只是增加了一個(gè)庫(kù)。打個(gè)比方,Rxjava比較難上手吧,不懂Rxjava的人看Rxjava像看天書,更不知從何寫起。kotlin學(xué)起來(lái)比Rxjava簡(jiǎn)單的多。
作為一名程序猿,我是非常追求代碼的簡(jiǎn)潔高效。在代碼簡(jiǎn)潔上,kotlin簡(jiǎn)直是神器,太和我心意了。由于要兼容低版本,之前就一直在用java的lambda表達(dá)式插件,但是很多java8的特性還是用不了。kotlin全部能做到,而且更好。在易理解的基礎(chǔ)上,能用1行代碼搞定的事我絕不會(huì)寫兩行。用了kotlin,我自己寫的很多基礎(chǔ)函數(shù)都用不著了。真正的Enjoy Coding!
也說(shuō)一下目前遇到的一些問(wèn)題
由于集成了kotlin包,apk會(huì)增大約0.5M。這看你的項(xiàng)目是否能接受了,我覺得還行。
目前沒發(fā)現(xiàn)什么大坑。在java-kotlin互相調(diào)用時(shí)要小心,koltin如果不注明,是強(qiáng)制不為空的。如果你的java代碼有良好的習(xí)慣,出入?yún)⒍甲⒚髁?code>@Nullable
@Nonnull
,就沒什么問(wèn)題了
安裝與配置
我的android studio 沒有升級(jí)3.0預(yù)覽版,使用的還是2.3版本。
-
首先更新kotlin語(yǔ)言插件
屏幕快照 2017-05-30 下午6.17.38.png - 工程里添加如下插件配置
//必須
apply plugin: 'kotlin-android'
//快捷的findviewfindid操作,建議加上
apply plugin: 'kotlin-android-extensions'
然后是依賴路徑
buildscript {
//可能由于androidstudio版本原因,老提示我這里使用1.1.2-3版本,最新應(yīng)該是1.1.2-4,根據(jù)提示來(lái)即可
ext.kotlin_version = '1.1.2-3'
repositories {
jcenter()
//阿里的maven倉(cāng)國(guó)內(nèi)鏡像,如果gradle下載很慢,建議使用該倉(cāng)庫(kù)
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
}
}
最后是編譯依賴的倉(cāng)庫(kù),用著這個(gè)就行了。
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
注意幾點(diǎn):
- 如果之前使用了依賴于注解的庫(kù)如Dragger,databinding等,需要額外的配置,詳情請(qǐng)參考官網(wǎng)
- Anko 是一個(gè)封裝了很多android操作的庫(kù),比如ui操作、異步操作、數(shù)據(jù)庫(kù)操作等等。不過(guò)我目前覺得還用不著,就沒加。感興趣的同學(xué)可以自己去添加。
ok, 可以進(jìn)入kotlin世界了!
我主要是參考了這本書 《Kotlin for Android developers》 ,加上一些自己的理解。內(nèi)容不多,看幾遍就記得差不多了。剛學(xué)習(xí)kotlin時(shí)可以下載下來(lái),使用時(shí)隨時(shí)查閱。
Koltin的類
kotlin的變量申明 val
是不可變變量,相當(dāng)于java里的final
。var
是可變變量,一般情況盡量使用val
。如果使用var
一般都需要判空
val i = 7 //自動(dòng)類型推導(dǎo)
val str:String = "hello"http://也可以顯式的指明類型
var name: String? = null//可變變量一般要注意使用安全操作符? ,使用時(shí)都要加上? val length = name?.length
這里有個(gè)小坑,如果沒加?
傳入了空參數(shù)是,kotlin會(huì)強(qiáng)制判空拋異常。
只要是Java語(yǔ)言有交互的參數(shù),除非是100%確定不為空,否則請(qǐng)務(wù)必都加上安全操作符
?
。
類繼承
class CustomView(context: Context?, attrs: AttributeSet?) : View(context, attrs)
構(gòu)造函數(shù)
額外添加一個(gè)屬性name
class CustomView(val name:String, context: Context?, attrs: AttributeSet?) : View(context, attrs)
添加其他構(gòu)造函數(shù)
class CustomView(context: Context?, attrs:AttributeSet?) : TextView(context, attrs){ constructor(name: String, context: Context?, attrs:AttributeSet?):this(context, attrs) { text = name } }
另外,kotlin不需要new操作符了,創(chuàng)建類直接調(diào)用其構(gòu)造方法,就像使用普通函數(shù)那樣。
val view = CustomView(context, attrs)
Kotlin的方法
方法申明差不多,動(dòng)手寫一下很快就明白了。
默認(rèn)參數(shù)特別好用! 終于可以不用寫一大堆同名函數(shù)了
動(dòng)態(tài)方法擴(kuò)展相當(dāng)于將一大堆Util換種寫法
比如異步加載圖片的封裝,java這樣寫
public static void setImageUriAsync(@NonNull ImageView iv, String uri, boolean round) {
...
}
public static void setImageUriAsync(@NonNull ImageView iv, String uri) {
setImageUriAsync(iv, uri, false);
}
kotlin這樣寫:
fun ImageView.setImageUrlAsync(url: String?, isRound: Boolean = false) {
...
}
調(diào)用時(shí)就當(dāng)做imageview的普通方法使用即可
iv.setImageUrlAsync(url)
iv.setImageUrlAsync(url, true)
注意一點(diǎn)
在java里,所有的方法都要在聲明在類里,一般一個(gè)類也只能有一個(gè)pulic方法。kotlin的方法可以獨(dú)立放在類外面,左右全局使用,比如前面提到ImageView擴(kuò)展方法就要單獨(dú)放在類外部。kotlin一個(gè)文件可以申明多個(gè)全局方法,聲明多個(gè)public類。就是說(shuō),很多東西都能放在kotlin一個(gè)文件里。
Koltin的Null處理
使用安全操作符?
可以省略很多無(wú)意義判空操作
不多說(shuō),直接上代碼,一看就都明白了。
以前這樣寫
if (adapter != null) {
List<CmdNotice> list = adapter.getDatas();
if (list != null) {
for (CmdNotice it :list) {
if (it.getId() == notice.getId()) {
it.setStatus(notice.getStatus());
adapter.notifyDataSetChanged();
break;
}
}
}
}
現(xiàn)在這樣寫
adapter?.datas?.firstOrNull({ it.id == notice.id })?.let {
it.status = notice.status
adapter?.notifyDataSetChanged()
}
靜態(tài)常量,靜態(tài)函數(shù),單例
如果一個(gè)類里都是靜態(tài)常量和靜態(tài)函數(shù),直接在最外面寫
object Const{
val MSG_1 = 1
fun getCurrentDate():Date{
return Date()
}
}
如果是在普通類里有靜態(tài)變量,以及單例,這樣寫
class MyCache{
companion object {
val TYPE = 1 //常量
val instance = MyCache() //單例
}
}
這樣調(diào)用
MyCache.TYPE
MyCache.instance
kotlin的inline(內(nèi)聯(lián))函數(shù)
內(nèi)聯(lián)函數(shù)與一般的函數(shù)不同,在編譯時(shí)會(huì)做替換,少了普通函數(shù)調(diào)用的壓棧出棧,更高效。因?yàn)槭翘鎿Q,所以可以識(shí)別傳入的泛型
比如
inline fun <reified T> getClassName():String{ return T::class.java.name }
直接這樣調(diào)用
val name = getClassName<AppCompatActivity>()
可以傳入代碼塊,比如一個(gè)異步線程操作的代碼塊
object MyExecutor{
val instance: ExecutorService = Executors.newCachedThreadPool()
}
inline fun doSync(crossinline block: () -> Unit) {
MyExecutor.instance.execute { block() }
}
//調(diào)用如下。 傳入的block代碼塊可以直接放在函數(shù)后面的{}里。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
doSync{
//Code: Request network
}
}
Kotlin基礎(chǔ)庫(kù)里大量的便捷操作以及Anko庫(kù)里很多操作都是使用inline
函數(shù)完成的。常用的when
, apply
, let
,以及對(duì)list數(shù)組封裝的各種操作firstOrNull
,filter
等都是內(nèi)聯(lián)函數(shù)完成的。
Koltin函數(shù)需要傳入的代碼塊可以直接放在函數(shù)名的大括號(hào)里,不需要再用小擴(kuò)號(hào)包起來(lái)。這樣的話,很多調(diào)用就非常簡(jiǎn)潔
比如Anko庫(kù)里的async
, uiThread
,異步操作的寫法比Rxjava簡(jiǎn)單的多!
async{
//Do step1 cost time
uiThread { toast("complete step1") }
//Do step2 cost time
uiThread { toast("complete step2")}
}
而且其寫法很巧妙,只保存了外部Activity的弱引用,如果在異步執(zhí)行過(guò)程中Activity銷毀了uiThread則不會(huì)調(diào)用,防止內(nèi)存泄漏。
FindViewById
由于有了插件kotlin-android-extensions
.
Activity
里可以這樣寫,不需要在額外申明TextView變量了。所以注意xml文件里id的命名使用駝峰寫法
setContentView(R.layout.main)
tvTitle.setOnClickListener { toast("hello") }
Adapter
里這樣寫, ViewHolder
完全不需要了
view.tvName.text = notice.name
view.tvNumber.text = ""
view.ivIcon.setImageUrlAsync(icon, true)
其他
注意在kotlin中
==
相當(dāng)于java中的equal
函數(shù),===
相當(dāng)于java中的==
。不過(guò)一般情況加==
就夠了。kotlin中沒有基本類型,所有的如Int,Long都是對(duì)象。kotlin中沒有三元操作符。可以用
if else
,或者?:
代替。
java:String a = result?"true":"false"
kotlin:val a = if (result) "true" else "false"
?:
表示先判斷前面是否為空,為空的話就返回后面的
java:String b = (a==null)?a:"true"
kotlin:val b=a?:"true"
因?yàn)槎际腔贘VM,Kotlin的所有操作java當(dāng)然都能做到,但是kotlin更簡(jiǎn)潔容易理解!
先到這里,如有問(wèn)題歡迎指正,大家共同進(jìn)步!