Android 中使用 Kotlin 快速入門

一、類與方法

1,類

  • 類的聲明

    class Bar(var b: Int): Foo() {
        var c = 1
        init {
            println("class initializer")
        }
    
        constructor(): this(1) {
            println("secondary constructor")
        }
    }

    Bar類在這裏繼承了Foo類,Bar類有兩個構造函數,直接在Bar類頭的是primary constructor,另外一個構造函數使用constructor關鍵字定義,注意必須要先調用primary constructor,另外,init標明的是class initializer,每個構造函數都會首先調用class initializer裏面的代碼,再調用構造函數

  • 創建類的實例,不需要 new

    var bar = Bar()
  • 繼承

    內定義默認是 final 的,要想能被繼承,基類頭必須有 open 註解

  • Inner class

    class Outer {
        class Inner {      
        }
    }

    與 Java 不同,Kotlin 中所有的內部類默認就是靜態的,這樣可以減少很多內存泄露的問題。如果需要在內部類中引用外部類對象,可以在Inner類的聲明前加上inner關鍵字,然後在Inner類中使用標記的this:this@Outer來指向外部類對象

  • Singleton

    object Single {
        var c = 1
    
        fun foo() = println("foo")
    }

    單利對象用 object 關鍵字表示,可以直接使用 Single.foo() 來調用了

2,接口

interface Interface {
    fun foo() {
        println(1)
    }
    fun bar()
}

可以帶有默認的實現方法,並且不允許通過屬性來維護狀態。

3,函數

  • 函數聲明

    fun foo(va: Int): Int {
        return 1
    }
  • 也可以使用單行聲明

    fun foo(va: Int): Int = 1
  • 重載

    與類的派生一樣,允許重載的方法要有open註解,而在派生類中重載時要使用override註解

    override fun foo(va: Int): Int {
        return 2
    }

4,修飾符

5,成員變量的 Get 與 Set

注:
1,類和方法默認定義都是 final,以此來提高效率。類想要被繼承用 open 關鍵字
2,類 和 成員變量 默認是 public 修飾

二、語法

1,語法糖,對類的擴充

在不修改類的原始定義的情況下實現對類的擴展,如下面的代碼爲Person類增加了一個名爲isTeenager的擴展:

fun Person.isTeenager(): Boolean {
    return age in 13..19
}

2,排除空指針

  • 定義一個爲空的變量是需要加上 ? 符號

    var text: String? = null
  • 操作一個可能爲空的對象時,同樣要加上 ? 符號

    var length = text?.length
  • 如果將該變量傳遞給函數,在參數後面需要加 !! 符號

    if (text != null) {
        customPrint(text!!)
    }
  • 如何去掉 !! 符號呢,當代碼充滿該符號時顯然很不優雅,這時可以使用 let 函數

    text?.let { customPrint(it) }
  • 如果遇到多個參數的情況,你可以選擇嵌套多個 let,但這樣可讀性並不好。比如:

    if (mUserName != null && mPhotoUrl != null) {
       uploadPhoto(mUserName!!, mPhotoUrl!!)
    }

    這時你可以構建一個全局函數:

    fun <T1, T2> ifNotNull(value1: T1?, value2: T2?, bothNotNull: (T1, T2) -> (Unit)) {
       if (value1 != null && value2 != null) {
           bothNotNull(value1, value2)
       }
    }

    調用方式

    ifNotNull(mUserName, mPhotoUrl, {name, url ->
            uploadPhoto(name, url)
    })

3,高階函數和Lambda表達式

  • 例如給一個變量賦 lambda 表達式 {x,y->x+y}

    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
  • 定義一個可以傳表達式的高階函數

    fun doubleTheResult(x:Int, y:Int, f:(Int, Int)->Int): Int {
        return f(x,y) * 2
    }
  • 調用方法如下

    val result1 = doubleTheResult(3, 4, sumLambda)
    或
    val result2 = doubleTheResult(3, 4, {x,y -> x+y})

4,範圍表達式

  • 範圍創建只需要 .. 操作符,爲升序,例如:

    // 該範圍包含數值1,2,3,4,5
    val r1 = 1..5
  • 如果要表示降序,用 downTo 函數

    // 該範圍包含數值5,4,3,2,1
    val r2 = 5 downTo 1
  • 如果步長不是1,則需要使用step函數

    // 該範圍包含數值5,3,1
    val r3 = 5 downTo 1 step 2
    // 同理,升序的序列
    val r4 = 1..10 step 2

5,條件結構

  • if 表達式(類似於 Java 的 ?: 運算符)

    var age = 20
    val isEligibleToVote = if(age > 18) "Yes" else "No"
  • when表達式(類似於 Java 的 switch,但功能更強大)

    val age = 17
    
    val typeOfPerson = when(age){
        0 -> "New born"
        in 1..12 -> "Child"
        in 13..19 -> "Teenager"
        else -> "Adult"
    }

6,循環結構

使用 for..in 遍歷數組、集合及其它提供了迭代器的數據結構,語法同Java幾乎完全相同,只是用 in 操作符取代了 : 操作符

val names = arrayOf("Jake", "Jill", "Ashley", "Bill")

for (name in names) {
    println(name)
}

while 和 do..while 循環的語法與Java完全相同。

7,字符串模板

可以在字符串中嵌入變量表達式,例如:

val name = "Bob"
println("My name is ${name}") //打印"My name is Bob"

val a = 10
val b = 20
println("The sum is ${a+b}") //打印"The sum is 30"

三、XML 佈局 + kotlin-android-extensions

1, 通常在 xml 中查找控件的寫法

val name = find<TextView>(R.id.tv_name)
// 等同於 findViewById()
val name = findViewById(R.id.tv_name) as TextView
name.text="張三"

2,如果使用擴展後,可以直接調用並賦值

tv_name.text="張三"

環境配置

1,項目下面的 build.gradle 加入如下代碼:

buildscript {

    ext.kotlin_version ="1.0.4"

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

2,app 下面的 build.gradle 加入如下代碼:

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    sourceSets{
        main.java.srcDirs+='src/main/kotlin'
    }
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    compile 'org.jetbrains.anko:anko-sdk25:0.10.0-beta-1'// sdk15, sdk19, sdk21, sdk23 are also available
    compile 'org.jetbrains.anko:anko-appcompat-v7:0.10.0-beta-1'
}

3,Gradle Sync

4,菜單欄 —> Code —> Convert Java File to Kotlin File

Anko Layout

一、優點

1,運行速度快。XML佈局是在運行時解析的,也就是說XML需要從資源文件中獲取,然後 XmlPullParser 需要解析所有的元素並一個一個的創建它們。還要解析元素的屬性,然後設置,這個過程非常繁重。

2,類型安全,不再需要那麼多的 findById() 之後的類型轉換。

3,null 安全,Kotlin 裏,如果一個變量用?表示爲可空,並且使用?之後再調用的時候,即使變量爲空也不會引發異常。

4,代碼複用,可以通過繼承AnkoComponent的方式實現代碼複用。XML佈局是每一個Activity,每一個View各自專屬一個,代碼複用比較少。

二、缺點

1,Anko DSL 佈局不能預覽。雖然有一個叫 Anko Preview Plugin 的預覽插件,但是每次修改後都需要 make 下才能預覽,關鍵是在新版本 Android Studio2.2 以上都不支持。

  • 筆者在 Android studio2.3 上安裝該插件,導致重啓後無法進入項目界面。
  • 幸好在啓動頁面的左下角有一個 Config 選項,點擊其中的 Plugin,卸載 Anko Preview 插件纔可以正常啓動。

2,定義 id 比較繁瑣,需要定義一個變量,或者在 values 資源文件下定義 ids。不用 id 行不行呢?你去問問 RelativeLayout 答應不答應吧。

3,如果定義在 xml 的話,可以直接通過 id 使用對應的 View(XML 佈局 + kotlin-android-extensions 的方式),但是在 Anko DSL 佈局的話,只能通過定義變量的方式來實現。

4,動態替換外部資源以達到換膚的效果,那麼 XML 顯然比 Kotlin 代碼要來得容易:前者可以編譯成一個只有資源的 apk 供應用加載,後者的話就得搞一下動態類加載了。

三、引用方式

// 繼承 AnkoComponent 創建佈局
class LoginLayout<T> : AnkoComponent<T> {

    override fun createView(ui: AnkoContext<T>): View {
        return with(ui){
            ...
        }
    }
}

// Activity 中引用
override fun onCreate(savedInstanceState: Bundle?) {
    LoginLayout<MainActivity>().setContentView(this)
}

// Fragment 中引用
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    var view = LoginLayout<LoginFragment>().createView(AnkoContext.create(context, LoginFragment()))
    return view
}

四、常用語法

1,定義 TextView

textView("Hello") {
    textSize = 16f
    textColor = Color.RED
    backgroundResource = R.drawable.shape_et_bg
    gravity = Gravity.CENTER
}.lparams(matchParent, wrapContent){
    margin = dip(12)
    padding = dip(2)
}

2,提取樣式

// 給 EditText 擴展樣式方法
fun EditText.commonStyle(){
    textSize = 16f
    backgroundResource = R.drawable.shape_et_bg
}

// 直接在佈局的後面添加上
.style {
    view ->
    when (view) {
        is Button -> {
            view.gravity = Gravity.CENTER
        }
        is TextView -> {
            view.gravity = Gravity.LEFT
            view.textSize = 20f
            view.textColor = Color.DKGRAY
        }
    }
}

3,設置點擊事件

var etInput = editText {
    hint = "請輸入文字"
    commonStyle()
}

button("點我"){
    // 在按鈕屬性內部設置點擊事件
    onClick {
        toast("輸入的內容:${etInput.text}")
    }
}

// 通過變量 + . 的方式設置
etInput.onClick { 

}

4,佈局方式

val ID_USERNAME = 1

// 垂直佈局,== LinearLayout + orientation="vertical"
verticalLayout {  }
// 相對佈局,需要使用到 ID
relativeLayout {
    textView("姓名") {
        id = ID_USERNAME
    }
    textView("描述") {

    }.lparams {
        below(ID_USERNAME)
        alignParentLeft()
    }
}
// 線性佈局
linearLayout {
    orientation = LinearLayout.HORIZONTAL
}
frameLayout { }
tableLayout { }

5,ui: AnkoContext

// 包含的變量
val ctx: Context
val owner: T
val view: View

// 例如,可以通過 owner 直接調用外部 Activity 的方法
override fun createView(ui: AnkoContext<T>): View {
    if (ui.owner is Activity) {
        (owner as Activity).onBackPressed()
    }
}

參考鏈接

Kotlin Primer·第二章·基本語法 https://kymjs.com/code/2017/02/04/01/

http://blog.csdn.net/io_field/article/details/53365834

只需五分鐘,開始使用Kotlin開發Android
https://barryhappy.github.io/2016/10/20/start-kotlin-in-5-mins/

登陸註冊 Demo
http://blog.csdn.net/xiehuimx/article/details/72354371

Kotlin 系統入門到進階 視頻教程 https://github.com/enbandari/Kotlin-Tutorials

官方文檔:https://www.kancloud.cn/pholance/kotlin/125094

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章