美文网首页
Kotlin小结

Kotlin小结

作者: DreamMeng | 来源:发表于2022-08-04 23:59 被阅读0次

    一、混合开发配置

    新建一个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

    相关文章

      网友评论

          本文标题:Kotlin小结

          本文链接:https://www.haomeiwen.com/subject/ilxubrtx.html