Kotlin Android開發(fā)一些心得

一周前開始學(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

  1. Google已經(jīng)明確kotlin為第一官方語(yǔ)言。我相信Google的決意,就像當(dāng)初毫不猶豫的拋棄eclipse轉(zhuǎn)向as。kotlin已經(jīng)是不可避免的大勢(shì)所趨了。

  2. Kotlin與java代碼完全兼容。使用kotlin就好像只是增加了一個(gè)庫(kù)。打個(gè)比方,Rxjava比較難上手吧,不懂Rxjava的人看Rxjava像看天書,更不知從何寫起。kotlin學(xué)起來(lái)比Rxjava簡(jiǎn)單的多。

  3. 作為一名程序猿,我是非常追求代碼的簡(jiǎn)潔高效。在代碼簡(jiǎn)潔上,kotlin簡(jiǎn)直是神器,太和我心意了。由于要兼容低版本,之前就一直在用java的lambda表達(dá)式插件,但是很多java8的特性還是用不了。kotlin全部能做到,而且更好。在易理解的基礎(chǔ)上,能用1行代碼搞定的事我絕不會(huì)寫兩行。用了kotlin,我自己寫的很多基礎(chǔ)函數(shù)都用不著了。真正的Enjoy Coding!

也說(shuō)一下目前遇到的一些問(wèn)題

  1. 由于集成了kotlin包,apk會(huì)增大約0.5M。這看你的項(xiàng)目是否能接受了,我覺得還行。

  2. 目前沒發(fā)現(xiàn)什么大坑。在java-kotlin互相調(diào)用時(shí)要小心,koltin如果不注明,是強(qiáng)制不為空的。如果你的java代碼有良好的習(xí)慣,出入?yún)⒍甲⒚髁?code>@Nullable @Nonnull,就沒什么問(wèn)題了

安裝與配置

參考kotlin官網(wǎng)

我的android studio 沒有升級(jí)3.0預(yù)覽版,使用的還是2.3版本。

  1. 首先更新kotlin語(yǔ)言插件


    屏幕快照 2017-05-30 下午6.17.38.png
  2. 工程里添加如下插件配置
//必須
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):

  1. 如果之前使用了依賴于注解的庫(kù)如Dragger,databinding等,需要額外的配置,詳情請(qǐng)參考官網(wǎng)
  2. 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里的finalvar是可變變量,一般情況盡量使用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ù)組封裝的各種操作firstOrNullfilter等都是內(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)

其他

  1. 注意在kotlin中== 相當(dāng)于java中的equal函數(shù),=== 相當(dāng)于java中的==。不過(guò)一般情況加==就夠了。kotlin中沒有基本類型,所有的如Int,Long都是對(duì)象。

  2. 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)步!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容