Kotlin小结

一、混合开发配置

新建一个kotlin类,若没配置过kotlin,android studio 会有提示“kotlin not configured”


image.png
image.png

build.grade中会自动添加kotlin的相关配置


image.png

二、 运行项目可能会出现:

问题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内置变量类型

image.png

3.3、Kotlin 的引用类型和基本类型

java中的变量有引用类型和基本类型
kotlin中变量只有引用类型,但出于高性能的需求,kotlin编译器会在java字节中改用基本类型

3.4、查看kotlin 字节码

image.png

image.png

四、函数与函数类型

image.png

4.1 函数参数

  • 默认值参
    如果不打算传入参数,可以预先给参数设定默认值
fun main() {
    fix("jase")
}


private fun fix(name: String , age:Int =20) {
    println("$name's age $age") 
}
  • 具名参数
    使用具名参数,可以不用管参数的顺序
fun main() {
    fix(age = 30,name ="Rose")
}

private fun fix(name: String , age:Int =20) {
    println("$name's age is $age")
}
  • 反引号中的函数名
  • kotlin中允许用空格和特殊符号来命名函数,但要用反引号包括起来
fun main() {
    `*34455473210sss`()
}
fun `*34455473210sss`(){
    println("函数名中带有反引号")
}
  • 为了支持Java与kotlin互操作,而它们都有不同的预留关键字不能作为函数名,使用反引号包括函数名就能避免冲突

4.2 匿名函数

  • 和具名函数不一样,除极少数情况下,匿名的返回不需要显式调用return关键字,它会隐式或自动返回函数体最后一行的执行结果
fun main() {
 //可以匿名函数可以作为变量
// (Int,Int)->Int 是变量sum的类型,sum是函数类型的变量
//它需要两个Int型参数,返回值是Int型
    val sum:(Int,Int)->Int ={ a,b->
        a+b
    }

    println(sum(10,20))
}

  • 类型推断
    当把一个匿名函数赋值给一个变量时,就不要显示的写明变量的类型了
fun main() {

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

    println(sum(10,20))

    val sum1 = {a:Int,b:Int->
        a+b
    }
}
  • it关键字
    当定义只有一个参数的匿名函数时,可以使用it关键字来表示参数名。当超过一个参数,it就不能用了
fun main() {
    val blessFuction:(String)->String ={
        val holiday = "New Year"
        "$it happy $holiday"
    }
    
    println(blessFuction("zhangsan"))
}

五、null安全调用

  • kotlin更多的将运行时可能出现的null问题,以编译时错误的方式,提前在编译期强迫我们重视起来,而不是等到运行时报错,防患于未然,提高我们程序的健壮性。
  • 为了避免NullPointerException,kotlin不允许我们给非空变量赋予null值,除非你手动接管安全管理

手动接管安全管理:

  • 选项一:安全调用操作符?.
    如果变量值为null,就跳过函数调用
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问题编译时,不会报错,只有运行时才会出现

    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 主构造函数

//主构造函数跟在类名后面 _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次构造函数

与主构造函数应用的是次要函数,可以定义多个次构造函数

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关键字可以声明一个只产生一次的对象实例----单例,而且可以实现类似静态类的效果。

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

fun main() {
   AppConfig.setSomthing()
    //只会产生一个实例
    println(AppConfig)
    println(AppConfig)

}

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

8.2 对象表达式

有时候你不一定非要定义一个新的命名类不可,也许你需要一个现有类的某种变种实例,但只需要用一次,事实上对这种用完一次就丢的类实例,连命名都可以省略。这个匿名类依然遵循object关键字的特性,只会实例化一次。

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

8.3 伴生对象

  • 如果你想把一个对象的初始化和另外一个类实例绑定在一起,可以用伴生对象,用companion关键字声明伴生对象,一个类中只能有一个伴生对象。
  • Kotlin中没有static关键字,如果想实现某个方法或某个属性实现静态,可以通过伴生对象实现
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)

九、协程的简单使用

协程是轻量级线程,使用协程可以很方便的进行线程切换,减少回调

//导入依赖
  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中常用的协程api:

  • GlobalScope 生命周期是进程级别的,即使activity和fragment已经销毁,协程依
    然执行
  • MainScope 在Activity中使用,需在onDestory() 中取消协程
  • 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为例简单讲解协程的使用

实例1

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

        lifecycleScope.launch {
            delay(2000)
            Log.d(TAG, "MainScope: " + Thread.currentThread().name)
            Log.d(TAG, "MainScope: " + "协程结束")
        }

        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: 协程结束

  • 协程内的阻塞delay(2000) 并未阻塞线程外的主线程执行

实例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: " + "协程结束")
            }
            //自动切换到主线程,可进行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: 协程结束
2022-08-04 23:21:14.922 4251-4251/com.example.coroutines D/MainActivity: lifecycleScope: main

实例三

多任务顺序执行

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容