Kotlin小結

一宪睹、混合開發(fā)配置

新建一個kotlin類,若沒配置過kotlin,android studio 會有提示“kotlin not configured”


image.png
image.png

build.grade中會自動添加kotlin的相關配置


image.png

二、 運行項目可能會出現(xiàn):

問題1

The minCompileSdk (32) specified in a
dependency's AAR metadata (META-INF/com/android/build/gradle/aar-metadata.properties)
is greater than this module's compileSdkVersion (android-29).
Dependency: androidx.core:core:1.9.0-alpha05.

解決方法

image.png

問題2

路由框架不能正常跳轉頁面丙猬,點擊首頁導航tab沒有反應

解決方法:

//    annotationProcessor "com.github.Dovar66.DRouter:router-compiler:${rootProject.ext.routerVersion}"
    //add for 路由框架找不到kolin類
    kapt  "com.github.Dovar66.DRouter:router-compiler:${rootProject.ext.routerVersion}"

問題3 unresolved reference: BR

是目前kotlin-android-extensions暫時還不支持跨模塊,
氧枣,在模塊的build.gradle中添加Kotlin-apt插件

apply plugin: 'kotlin-kapt'

三、kotlin的變量定義與類型

3.1曙旭、聲明變量(val 聲明不可變變量盗舰,var聲明可變變量)

   val a:Int = 0 // 變量名:返回類型
    var b = "I'm kotlin" //返回類型可以省略,自動推動

3.2 kotlin內(nèi)置變量類型

image.png

3.3桂躏、Kotlin 的引用類型和基本類型

java中的變量有引用類型和基本類型
kotlin中變量只有引用類型钻趋,但出于高性能的需求,kotlin編譯器會在java字節(jié)中改用基本類型

3.4剂习、查看kotlin 字節(jié)碼

image.png

image.png

四蛮位、函數(shù)與函數(shù)類型

image.png

4.1 函數(shù)參數(shù)

  • 默認值參
    如果不打算傳入?yún)?shù),可以預先給參數(shù)設定默認值
fun main() {
    fix("jase")
}


private fun fix(name: String , age:Int =20) {
    println("$name's age $age") 
}
  • 具名參數(shù)
    使用具名參數(shù)鳞绕,可以不用管參數(shù)的順序
fun main() {
    fix(age = 30,name ="Rose")
}

private fun fix(name: String , age:Int =20) {
    println("$name's age is $age")
}
  • 反引號中的函數(shù)名
  • kotlin中允許用空格和特殊符號來命名函數(shù)失仁,但要用反引號包括起來
fun main() {
    `*34455473210sss`()
}
fun `*34455473210sss`(){
    println("函數(shù)名中帶有反引號")
}
  • 為了支持Java與kotlin互操作,而它們都有不同的預留關鍵字不能作為函數(shù)名们何,使用反引號包括函數(shù)名就能避免沖突

4.2 匿名函數(shù)

  • 和具名函數(shù)不一樣萄焦,除極少數(shù)情況下,匿名的返回不需要顯式調用return關鍵字冤竹,它會隱式或自動返回函數(shù)體最后一行的執(zhí)行結果
fun main() {
 //可以匿名函數(shù)可以作為變量
// (Int,Int)->Int 是變量sum的類型拂封,sum是函數(shù)類型的變量
//它需要兩個Int型參數(shù),返回值是Int型
    val sum:(Int,Int)->Int ={ a,b->
        a+b
    }

    println(sum(10,20))
}

  • 類型推斷
    當把一個匿名函數(shù)賦值給一個變量時鹦蠕,就不要顯示的寫明變量的類型了
fun main() {

    val sum:(Int,Int)->Int ={ a,b->
        a+b
    }

    println(sum(10,20))

    val sum1 = {a:Int,b:Int->
        a+b
    }
}
  • it關鍵字
    當定義只有一個參數(shù)的匿名函數(shù)時冒签,可以使用it關鍵字來表示參數(shù)名。當超過一個參數(shù)钟病,it就不能用了
fun main() {
    val blessFuction:(String)->String ={
        val holiday = "New Year"
        "$it happy $holiday"
    }
    
    println(blessFuction("zhangsan"))
}

五镣衡、null安全調用

  • kotlin更多的將運行時可能出現(xiàn)的null問題,以編譯時錯誤的方式档悠,提前在編譯期強迫我們重視起來廊鸥,而不是等到運行時報錯,防患于未然辖所,提高我們程序的健壯性惰说。
  • 為了避免NullPointerException,kotlin不允許我們給非空變量賦予null值,除非你手動接管安全管理

手動接管安全管理:

  • 選項一:安全調用操作符?.
    如果變量值為null缘回,就跳過函數(shù)調用
fun main() {
   var str :String? = readLine()
   //str.capitalize()
   println(str?.capitalize())
}
  • 選項二:使用非空斷言操作符
    !!.操作符又稱感嘆號操作符吆视,當變量為null值時典挑,會報NullPointerException
fun main() {
   var str :String? = readLine()
   //str.capitalize()
   str!!.capitalize()
}
  • 選項三:使用if判斷null值的情況
  • 選項四:使用空合并操作符?:

?:操作符的意思是當左側的求值結果為null時,就用右側的結果值

fun main() {
   var str :String? = readLine()
   val safeStr = str?:"butterfly"
    println(safeStr)
}

坑:kotlin調用java方法時啦吧,有些null問題編譯時您觉,不會報錯,只有運行時才會出現(xiàn)

    fun getAppEntrance() {
        userModel.getAppEntrance(object : RequestListener {
    //override fun onSuccess(jsonObject: JSONObject)  
   //如果這里沒有授滓?琳水,后臺返回的jsonobject為null,運行到這里時應用會直接崩潰,
   //崩潰的原因時般堆,將一個空值付給了非空值
            override fun onSuccess(jsonObject: JSONObject?) {
                
            }

            override fun onFailure(error: ErrorResponeBean?) {

            }

        })
    }

六 在孝、List/Map

6.1List

 //不可變list
  val list = listOf(1,2,3)
//可變list,可以進行add/remove等操作
  val list = mutableListOf(,"joke","rose","jack")
    list.add("jim")
    list.remove("joke")

遍歷list

val list = mutableListOf("joke","rose","jack")
    //for in
    for (str in list){
        println(str)
    }
    
   //forEach
    list.forEach {
        println(it)
    }
    
   //forEachIndexed
    list.forEachIndexed { index, s ->
        println("index = $index  value =$s")
    }

解構list

  val list = mutableListOf("joke","rose","jack")
   val(one,two,three) = list
    println(one)
    println(two)
    println(three)

6.2 map

  //不可變map
    var map = mapOf("jack" to 20,"jim" to 25)
    println(map["jack"])

//可變map
    val  mutableMap = mutableMapOf("jack" to 20,"jim" to 25)
     //插入元素
    mutableMap.put("week",20)
    mutableMap["robit"] = 30

   //刪除
    mutableMap.remove("jack")

遍歷map

    var map = mapOf("jack" to 20,"jim" to 25)
    map.forEach { (key, value) ->
        println("key =$key, value =$value")
    }

    map.forEach {
        println("${it.key}->${it.value}")
    }

七 類定義

7.1 主構造函數(shù)

//主構造函數(shù)跟在類名后面 _age是臨時變量,name 是成員變量
class Student(var name:String,_age:Int){
    var age = _age
}
fun main() {
    val mStudent = Student("rose",18)
    println(mStudent.name)
    println(mStudent.age)
}

7.2次構造函數(shù)

與主構造函數(shù)應用的是次要函數(shù)淮摔,可以定義多個次構造函數(shù)

class Student(var name:String,_age:Int,var idNumber:Int){
    var age = _age
    constructor(name:String):this(name,20,1001)
    constructor(name: String,idNumber: Int):this(name,20,idNumber){
        this.name = name.uppercase()
    }
}
fun main() {
    val mStudent = Student("rose",1002)
    println(mStudent.name)
    println(mStudent.age)
    println(mStudent.idNumber)
}
  • kotlin中的類默認是final的私沮,如果需要被繼承需用open修飾
open class Student(var name:String,_age:Int,var idNumber:Int){}
  • 方法也是,如需重寫和橙,也需用open修飾

八仔燕、object關鍵字的作用

8.1 對象聲明,使用object關鍵字可以聲明一個只產(chǎn)生一次的對象實例----單例,而且可以實現(xiàn)類似靜態(tài)類的效果魔招。

object AppConfig{
    init {
        println("loading config")
    }
    fun setSomthing(){
        println("please setSomthing")
    }
}

fun main() {
   AppConfig.setSomthing()
    //只會產(chǎn)生一個實例
    println(AppConfig)
    println(AppConfig)

}

loading config
please setSomthing
AppConfig@27f674d
AppConfig@27f674d

8.2 對象表達式

有時候你不一定非要定義一個新的命名類不可涨享,也許你需要一個現(xiàn)有類的某種變種實例,但只需要用一次仆百,事實上對這種用完一次就丟的類實例厕隧,連命名都可以省略。這個匿名類依然遵循object關鍵字的特性俄周,只會實例化一次吁讨。

 llDiamond.setOnClickListener(object : View.OnClickListener{
                override fun onClick(v: View?) {
                    
                }
            })

8.3 伴生對象

  • 如果你想把一個對象的初始化和另外一個類實例綁定在一起,可以用伴生對象峦朗,用companion關鍵字聲明伴生對象建丧,一個類中只能有一個伴生對象。
  • Kotlin中沒有static關鍵字波势,如果想實現(xiàn)某個方法或某個屬性實現(xiàn)靜態(tài)翎朱,可以通過伴生對象實現(xiàn)
open class BindPhoneNumberActivity : MyBaseActivity<ActivityBindPhoneNumberBinding, BindPhoneNumberViewModel>(){
    companion object{
        @JvmStatic
        fun jump(context: Context){
            jump(context,IntentUtil.SourceFrom.FROM_OTHER)
        }

        @JvmStatic
        fun jump(context: Context,from:IntentUtil.SourceFrom){
            val intent = Intent(context, BindPhoneNumberActivity::class.java)
            intent.putExtra(UserService.FROM,from)
            context.startActivity(intent)
        }
    }
}
//調用
BindPhoneNumberActivity.jump(this@BindPhoneNumberErrorActivity)

九、協(xié)程的簡單使用

協(xié)程是輕量級線程尺铣,使用協(xié)程可以很方便的進行線程切換拴曲,減少回調

//導入依賴
  implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-RC-native-mt'
  implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0-RC-native-mt'
     implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'//lifecycleScope
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'//viewModelScope

anroid中常用的協(xié)程api:

  • GlobalScope 生命周期是進程級別的,即使activity和fragment已經(jīng)銷毀凛忿,協(xié)程依
    然執(zhí)行
  • MainScope 在Activity中使用澈灼,需在onDestory() 中取消協(xié)程
  • viewModelScope 在ViewModel中使用,綁定ViewModel的生命周期,無需手動cancel
  • lifecycleScope 在Activity、Fragment中使用叁熔,會綁定Activity和Fragment的生命周期,無需手動cancel
//源碼中當DESTROYED時委乌,viewModelScope 、lifecycleScope 會自動取消
  override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
            lifecycle.removeObserver(this)
            coroutineContext.cancel()
        }
    }

以lifecycleScope為例簡單講解協(xié)程的使用

實例1

 private fun doSomeThing() {
        Log.d(TAG, "doSomeThing: " + "開始")

        lifecycleScope.launch {
            delay(2000)
            Log.d(TAG, "MainScope: " + Thread.currentThread().name)
            Log.d(TAG, "MainScope: " + "協(xié)程結束")
        }

        Log.d(TAG, "doSomeThing: " + "結束")
    }

2022-08-04 23:16:04.090 4094-4094/com.example.coroutines D/MainActivity: doSomeThing: 開始
2022-08-04 23:16:04.114 4094-4094/com.example.coroutines D/MainActivity: doSomeThing: 結束
2022-08-04 23:16:06.119 4094-4094/com.example.coroutines D/MainActivity: lifecycleScope: main
2022-08-04 23:16:06.119 4094-4094/com.example.coroutines D/MainActivity: lifecycleScope: 協(xié)程結束

  • 協(xié)程內(nèi)的阻塞delay(2000) 并未阻塞線程外的主線程執(zhí)行

實例2 線程切換

 private fun doSomeThing() {
        Log.d(TAG, "doSomeThing: " + "開始")

        lifecycleScope.launch {
            withContext(Dispatchers.IO){ //切換到IO 
                delay(2000)
                Log.d(TAG, "lifecycleScope: " + Thread.currentThread().name)
                Log.d(TAG, "lifecycleScope: " + "協(xié)程結束")
            }
            //自動切換到主線程荣回,可進行UI操作
            Log.d(TAG, "lifecycleScope: " + Thread.currentThread().name)

        }

        Log.d(TAG, "doSomeThing: " + "結束")

    }

2022-08-04 23:21:12.907 4251-4251/com.example.coroutines D/MainActivity: doSomeThing: 開始
2022-08-04 23:21:12.919 4251-4251/com.example.coroutines D/MainActivity: doSomeThing: 結束
2022-08-04 23:21:14.922 4251-4306/com.example.coroutines D/MainActivity: lifecycleScope: DefaultDispatcher-worker-1
2022-08-04 23:21:14.922 4251-4306/com.example.coroutines D/MainActivity: lifecycleScope: 協(xié)程結束
2022-08-04 23:21:14.922 4251-4251/com.example.coroutines D/MainActivity: lifecycleScope: main

實例三

多任務順序執(zhí)行

private fun doSomeThing2(){
        Log.d(TAG, "doSomeThing2: 開始")

        lifecycleScope.launch {
          val time =  measureTimeMillis {
              val a = getA()
              val b = getB()
              Log.d(TAG, "lifecycleScope: 結果${a+b}")
            }
            Log.d(TAG, "lifecycleScope: 用時$time")
        }
        Log.d(TAG, "doSomeThing2: 結束")
    }
    private suspend fun getA():Int{
        delay(2000)
        Log.d(TAG, "lifecycleScope: getA()")
        return 20
    }

    private suspend fun getB():Int{
        delay(1000)
        Log.d(TAG, "lifecycleScope: getB()")
        return 30
    }

2022-08-04 23:40:08.722 5361-5361/com.example.coroutines D/MainActivity: doSomeThing2: 開始
2022-08-04 23:40:08.735 5361-5361/com.example.coroutines D/MainActivity: doSomeThing2: 結束
2022-08-04 23:40:10.738 5361-5361/com.example.coroutines D/MainActivity: lifecycleScope: getA()
2022-08-04 23:40:11.742 5361-5361/com.example.coroutines D/MainActivity: lifecycleScope: getB()
2022-08-04 23:40:11.742 5361-5361/com.example.coroutines D/MainActivity: lifecycleScope: 結果50
2022-08-04 23:40:11.742 5361-5361/com.example.coroutines D/MainActivity: lifecycleScope: 用時3007

實例三 多任務并行

  private fun doSomeThing3(){
        Log.d(TAG, "doSomeThing3: 開始")
        lifecycleScope.launch {
            val time =  measureTimeMillis {
                val a = async { getA() }
                val b = async { getB() }
                Log.d(TAG, "lifecycleScope: 結果${a.await()+b.await()}")
            }
            Log.d(TAG, "lifecycleScope: 用時$time")
        }
        Log.d(TAG, "doSomeThing3: 結束")

    }

    private suspend fun getA():Int{
        delay(2000)
        Log.d(TAG, "lifecycleScope: getA()" +Thread.currentThread().name)
        return 20
    }

    private suspend fun getB():Int{
        delay(1000)
        Log.d(TAG, "lifecycleScope: getB()"+Thread.currentThread().name)
        return 30
    }

2022-08-04 23:44:41.873 5672-5672/com.example.coroutines D/MainActivity: doSomeThing3: 開始
2022-08-04 23:44:41.902 5672-5672/com.example.coroutines D/MainActivity: doSomeThing3: 結束
2022-08-04 23:44:42.907 5672-5672/com.example.coroutines D/MainActivity: lifecycleScope: getB()main
2022-08-04 23:44:43.904 5672-5672/com.example.coroutines D/MainActivity: lifecycleScope: getA()main
2022-08-04 23:44:43.905 5672-5672/com.example.coroutines D/MainActivity: lifecycleScope: 結果50
2022-08-04 23:44:43.905 5672-5672/com.example.coroutines D/MainActivity: lifecycleScope: 用時2005

實例4 多任務并行且線程切換

    private fun doSomeThing3(){
        Log.d(TAG, "doSomeThing3: 開始")
        lifecycleScope.launch {
            val time =  measureTimeMillis {
                val a = async(context = Dispatchers.IO){getA()}
                val b = async { withContext(Dispatchers.IO){
                    getB()
                } }
                Log.d(TAG, "lifecycleScope: 結果${a.await()+b.await()}")
            }
            Log.d(TAG, "lifecycleScope: 用時$time" +Thread.currentThread().name)
        }
        Log.d(TAG, "doSomeThing3: 結束")

    }



    private suspend fun getA():Int{
        delay(2000)
        Log.d(TAG, "lifecycleScope: getA()" +Thread.currentThread().name)
        return 20
    }

    private suspend fun getB():Int{
        delay(1000)
        Log.d(TAG, "lifecycleScope: getB()"+Thread.currentThread().name)
        return 30
    }

2022-08-04 23:55:49.991 6432-6432/com.example.coroutines D/MainActivity: doSomeThing3: 開始
2022-08-04 23:55:50.018 6432-6432/com.example.coroutines D/MainActivity: doSomeThing3: 結束
2022-08-04 23:55:51.029 6432-6487/com.example.coroutines D/MainActivity: lifecycleScope: getB()DefaultDispatcher-worker-1
2022-08-04 23:55:52.020 6432-6489/com.example.coroutines D/MainActivity: lifecycleScope: getA()DefaultDispatcher-worker-3
2022-08-04 23:55:52.021 6432-6432/com.example.coroutines D/MainActivity: lifecycleScope: 結果50
2022-08-04 23:55:52.021 6432-6432/com.example.coroutines D/MainActivity: lifecycleScope: 用時2008main

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遭贸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子心软,更是在濱河造成了極大的恐慌壕吹,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糯累,死亡現(xiàn)場離奇詭異算利,居然都是意外死亡册踩,警方通過查閱死者的電腦和手機泳姐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暂吉,“玉大人胖秒,你說我怎么就攤上這事∧降模” “怎么了阎肝?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肮街。 經(jīng)常有香客問我风题,道長,這世上最難降的妖魔是什么嫉父? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任沛硅,我火速辦了婚禮,結果婚禮上绕辖,老公的妹妹穿的比我還像新娘摇肌。我一直安慰自己,他們只是感情好仪际,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布围小。 她就那樣靜靜地躺著,像睡著了一般树碱。 火紅的嫁衣襯著肌膚如雪肯适。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天成榜,我揣著相機與錄音疹娶,去河邊找鬼。 笑死伦连,一個胖子當著我的面吹牛雨饺,可吹牛的內(nèi)容都是我干的钳垮。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼额港,長吁一口氣:“原來是場噩夢啊……” “哼饺窿!你這毒婦竟也來了?” 一聲冷哼從身側響起移斩,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤肚医,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后向瓷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肠套,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年猖任,在試婚紗的時候發(fā)現(xiàn)自己被綠了你稚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡朱躺,死狀恐怖刁赖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情长搀,我是刑警寧澤宇弛,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站源请,受9級特大地震影響枪芒,放射性物質發(fā)生泄漏。R本人自食惡果不足惜谁尸,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一舅踪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧症汹,春花似錦硫朦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞒斩,卻和暖如春破婆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胸囱。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工祷舀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓裳扯,卻偏偏與公主長得像抛丽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子饰豺,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

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