轻轻松松Kotlin快速入门(一)

最近在学习kotlin,记录下自己学习过程中的笔记。因为内容比较多,所以分为几篇文章。那么第一篇主要是以下的内容:


转载地址:https://zhuanlan.zhihu.com/p/417635072
原作者:啥都不懂的小白

变量、常量和类型

声明变量

在Java中声明变量

int a = 1;

在kotlin中声明变量

var a : Int = 1

可以看出在kotlin中声明变量的格式:

var 变量名 : 类型定义 = 赋值

只读变量

除了使用var来声明变量,还可有使用val来声明变量。但这二者的作用是不同的,val是只读变量,使用了val来定义变量后,该变量是不能改变的。其有些类似于Java中的final,但也有不同之处,后面会讲到。

var a : Int = 1
a = 10                      //没问题
val b : Int = 1
b = 10            //报错

类型推断

对于已声明并赋值的变量,允许省略类型定义

var a : Int = 1 
var s : String = "Hello World"
//可以直接写成
var a = 1
var s = "Hello World"

编译时常量

  • 编译时常量只能在函数之外声明,因为编译时常量必须在编译时赋值,而函数都是在运行时才调用,函数内的变量也是在运行时赋值,编译时常量要在这些变量赋值前就已存在。
  • 编译时常量只能是基本的八种数据类型,Int、Double、Float、Long……

可以将Kotlin代码转换成Java的代码来查看

可以发现kotlin中const val MAX其实就等效于java中的final static

数据类型

  • 在Java中有两种数据类型,除了八种基本数据类型,其余的都是引用类型

  • 而在Kotlin中只有引用类型,出于更高性能的需要,Kotlin编译器会自动在Java字节码中改用基本数据类型

其实区别主要是装箱方面不同,拿整数类型的变量解释,java中我们定义一个整型变量可以通过int(基本类型)或者Integer(引用类型)来定义一个整数类型。

//java中
int a = 1;      
Integer b = 2;   //自动装箱

而在Kotlin中,只有Int(引用类型)来定义整数类型。

var a : Int = 10;

但是Kotlin编译器会根据性能需要自动判断是否对该变量进行装箱。

var a: Int = 1 // unbox
var b: Int? = 2 // box
var list: List<Int> = listOf(1, 2) // box

条件语句

  • if/else if 表达式(和Java一样)

  • range表达式

  • in A…B,in关键字用来检查某个值是否在指定范围之内

val money = 10
if(money in 0..5){
    println("cheap")
}else if(money in 5..10){
    println("mid")
}else{
    println("expensive")
} 

输出:

mid
  • when表达式(其实就是java中的switch…case)
val money = 10
when (money) {
    in 0..5 -> {
        println("cheap")
    }
    in 5..10 -> {
        println("mid")
    }
    else -> {
        println("expensive")
    }
}

string模板

  • 模板支持在字符串的引号内放入变量值
  • 还支持字符串里计算表达式的值并插入结果
  • 格式 $变量名${表达式}
fun main(){
    val a = 10
    println("value = $a")

    val flag = false
    println("答案是${if(flag) "正确的" else "错误的"}")
}

输出

value = 10
答案是错误的

函数

函数头

//格式
private fun 函数名(函数参数):返回类型 {}
fun main(){
    println("value = ${getValue(100)}")
}

private fun getValue(money:Int):String{
    var value = "";
    value = when (money) {
        in 0..5 -> {
            "cheap"
        }
        in 5..10 -> {
            "mid"
        }
        else -> {
            "expensive"
        }
    }
    return value
}

输出

value = expensive

函数参数

  • 默认值参

  • 如果不打算传入值参,可以预先给参数指定默认值

fun main(){
    //如果所调用的方法参数已经给了默认值,可以不传参数
    println("value = ${getValue()}")
}

//可以给参数设置默认值,若调用该方法不穿参数的话,就直接使用该默认值
private fun getValue(money:Int = 100):String{
    var value = "";
    value = when (money) {
        in 0..5 -> {
            "cheap"
        }
        in 5..10 -> {
            "mid"
        }
        else -> {
            "expensive"
        }
    }
    return value
}
  • 具名函数参数

  • 如果使用命名值参,就可以不用管值参的顺序(参数多的时候用起来方便)

fun main(){
    println("value = ${test(f = 20,d = 30,b = 100,a = "hhh",c = 1,e = 21)}")
}

private fun test(a:String,b:Int,c:Int,d:Int,e:Int,f:Int):String{
    return a;
}

输出:

value = hhh

Unit函数

Kotlin中没有返回值的函数叫Unit函数,类似Java中的void。

fun main(){
    getValue()
}

private fun getValue(money:Int = 100):Unit{
    when (money) {
        in 0..5 -> {
            println("cheap")
        }
        in 5..10 -> {
            println("mid")
        }
        else -> {
            println("expensive")
        }
    }
}

输出:

expensive

匿名函数

定义时不取名字的函数,匿名函数通常整体传递给其他函数,或者从其它函数返回。通过匿名函数,能够在Kotlin中根据需要给标准函数指定特殊规则。

fun main(){
    //统计字符个数
    val num1 = "HAHAHAHAHDDC".count()
    //统计字符串中`H`字符的个数
    val numH = "HAHAHAHAHDDC".count({ letter ->
        letter == 'H'
    })
    println("num1 = $num1,numH = $numH")
}

输出

num1 = 12,numH = 5

上面统计字符创中‘H’的个数中,count()就是标准函数,括号中的{变量->函数体}就是匿名函数,是我为count()这个标准函数定义的一个规则,让count()去统计字符串中‘H’的个数。

现在可能会看不太懂为什么这段代码可以这么写,下面会解释。

匿名函数类型与隐式返回

  • 匿名函数也有类型,它可以当做变量进行赋值。
//格式
val 变量名:匿名函数  //变量类型是一个函数

例子:

fun main() {
   //变量a是一个函数类型,该函数无参,返回值为Int类型
    val a : () -> Int = {
        val b = 10
        val c = 20
        b + c
    }

    println(a())
}
  • 和具名函数不一样,匿名函数一般不需要return关键字来返回数据,匿名函数会隐式或自动返回函数体最后一行语句的结果

这里抛出一个问题,正常来讲函数是不能赋值给变量的,如下面这个例子

fun main() {
    val a = add()  //这是函数调用,没有问题
    val fun = add   //这是将函数赋值给fun这个变量,编译会报错
}

fun add() : Int{
    val b = 10
    val c = 20
    return b + c
}

那为什么匿名函数可以赋值给变量呢?匿名函数难道不是「函数」吗?继续往下看就会懂了。

匿名函数参数

和具名函数一样,匿名函数可以不带参数,也可以带一个或多个任何类型的参数,需要带参数时,参数的类型放在匿名函数的类型定义中,参数名则放在函数定义中

fun main() {
    val a : (Int) -> Int = { num->
        num + 20
    }

    println(a(10))
}

输出

30

it关键字

定义只有一个参数的匿名函数时,可以使用it关键字来表示参数名。但是当传入两个或两个以上的参数时,it关键字就不能用了

fun main() {
    val a : (Int) -> Int = {
        it + 20
    }

    println(a(10))
}

输出

30

类型推断

匿名函数类型也存在类型推断,当定义一个变量时,如果已把匿名函数作为变量赋值给它时,就不需要显示指明变量类型了

fun main() {
    /*val a : () -> Int = {
        val b = 10        val c = 20        b + c    }*/
    //上面注释这段代码等效下面这段
    val a  = {
        val b = 10
        val c = 20
        b + c
    }

    println(a())
}

输出

30

类型推断也支持带参数的匿名函数,但为了帮助编译器更准确地推断变量类型,匿名函数的参数名和参数类型必须要写

fun main() {
    /*val a : (Int,Int) -> Int = {a,b ->
        a + b    }*/
   //上面注释这段代码等效下面这段
    val a  = {a:Int,b:Int ->
        a + b
    }

    println(a(10,20))
}

输出

30

lambda

如果你学过Java,有没有发现上面Kotlin的匿名函数写法似曾相识,很像Java中的Lambda表达式。其实Kotlin中我们也将匿名函数称为lambda,将它定义为lambda表达式。

那Java和Kotlin的lambda有什么区别呢。刚刚上面也说了,在kotlin中,函数是可以作为变量的类型,也就是说函数是可以作为函数的参数来用的(有点绕口,后面详细讲下就明白了)。Java中我们是不能直接传递一个函数/方法的,当然借助接口可以实现类似的效果,但kotlin中直接支持传递函数无疑是方便了许多。

定义参数是函数的函数

在kotlin中支持函数的参数是另外一个函数,也就是说可以调用一个函数其参数可以是另外一个函数。

fun main() {
    //定义一个函数类型的变量
    val calStudentAge = {birYear:Int,year:Int ->
        year - birYear
    }
    //传入的最后一个参数就是我们上面定义的函数类型变量
    showStudentMsg("barry",2001,2021,calStudentAge)

}

//该函数的最后一个参数是一个名为getStudentAge的函数
fun showStudentMsg(name:String,birYear:Int,year:Int,getStudentAge : (Int,Int)->Int){
    println("${name}同学${birYear}年出生,现在是${year}年")
    println("所以${name}同学今年${getStudentAge(birYear,year)}岁了")
}

输出

barry同学2001年出生,现在是2021年
所以barry同学今年20岁了

简略写法

如果一个函数的lambda参数排在最后,或是唯一的参数,那么lambda参数的圆括号可以省略。

上面的调用showStudenMsg代码我可以直接这样改写

showStudentMsg("barry",2001,2021,{birYear:Int,year:Int ->
    year - birYear
})

此时我们的idea就会有以下的提示:

Lambda argument should be moved out of parentheses

也就是提示我们应将 Lambda 参数移出括号,因为此时就符合lambda参数排在最后的条件,所以正确的写法应该是:

showStudentMsg("barry",2001,2021) { birYear: Int, year: Int ->
    year - birYear
}

我们在看回匿名函数这节中最开始的那个例子

val numH = "HAHAHAHAHDDC".count({ letter ->
    letter == 'H'
})

现在可以理解为什么可以这么去写这段代码了吧,这是因为count这个函数参数支持我们传递一个函数。看下count函数的源码:

public inline fun CharSequence.count(predicate: (Char) -> Boolean): Int {
    var count = 0
    for (element in this) if (predicate(element)) ++count
    return count
}

通过源码可以看到count函数中的参数,是一个返回类型为Boolean,传递参数为Char类型,名字为predicate的函数。我把上面的调用改写一下可能会更好理解

val predicate = { letter:Char ->
    letter == 'H'
}

val numH = "HAHAHAHAHDDC".count(predicate)

首先定义一个类型为函数的变量predicate,然后调用count时传入这个predicate变量,count函数就会通过我们这个匿名函数,对字符串进行遍历,如果element == ‘H’,那么count就+1。

上面的调用还可以简写,刚刚说了如果匿名函数中只有一个参数,那么可以用it代替

val predicate = {
    it == 'H'
}
val numH = "HAHAHAHAHDDC".count(predicate)

并且count函数也符合lambda参数是唯一参数,所以可以写成

val numH = "HAHAHAHAHDDC".count{
    it == 'H'
}

函数内联

我们在使用lambda表达式时,它会被正常地编译成一个匿名类。说明每调用一次lambda表达式,一个额外的类就会被创建,并且如果lambda捕捉了某个变量,那么每次调用的时候都会创建一个新的对象,这会带来运行时的额外开销,导致使用lambda比使用一个直接执行相同代码的函数效率更低。

所以kotlin中提供了一种优化机制——内联(inline),有了内联,JVM就不需要使用lambda对象实例了。如果使用inline修饰符标记一个函数,在函数被调用的时候编译器并不会生成函数调用的代码,而是 使用函数实现的真实代码替换每一次的函数调用

可以来看下使用内联和不使用内联的字节码

未使用内联:

fun main() {
    showStudentMsg("barry",2001,2021) { birYear: Int, year: Int ->
        year - birYear
    }
}

fun showStudentMsg(name:String,birYear:Int,year:Int,getStudentAge : (Int,Int)->Int){
    println("${name}同学${birYear}年出生,现在是${year}年")
    println("所以${name}同学今年${getStudentAge(birYear,year)}岁了")
}

可以main函数里看到未使用内联的是会直接调用showStudentMsg这个函数,调用后会产生一个Function2类的对象getStudentAge,然后通过invoke方法来执行,这会增加额外的生成类和函数调用开销。

使用内联:

现在方法前加上inline修饰符

fun main() {
    showStudentMsg("barry",2001,2021) { birYear: Int, year: Int ->
        year - birYear
    }
}

inline fun showStudentMsg(name:String,birYear:Int,year:Int,getStudentAge : (Int,Int)->Int){
    println("${name}同学${birYear}年出生,现在是${year}年")
    println("所以${name}同学今年${getStudentAge(birYear,year)}岁了")
}

使用了inline修饰后,也就是showStudentMsg成为了内联函数,那么此时我们再看main函数中,这时就不会再去调用showStudentMsg这个函数了,而是直接将showStudentMsg函数中的代码粘贴到了相应调用的位置。就等于是直接用函数的真实代码替换了函数调用,节省了额外的生成类和函数调用开销。

当然内联函数不是万能的,以下情况避免使用内联函数:

  1. 像上面使用内联后,会发现字节码数量相比没有内联是大大增多。所以尽量避免对具有大量函数体的函数进行内联,这样会导致过多的字节码数量。

  2. 由于JVM对普通函数已经能够根据实际情况智能地判断是否进行内联优化,所以并不需要对其使用Kotlin的inline语法,那只会让字节码变得更加复杂。

  3. 使用lambda的递归函数无法内联,因为会导致真实代码复制替换无限循环

在上面的字节码中,我们可以看到showStudent这个函数中最后一个参数是一个Function类的引用,那就说明传递的参数是一个对象。可是我们在kotlin代码里面传递不是一个匿名函数吗,不应该是一个「函数」吗?下面就开始解密了

函数引用

调用带参数类型是函数的函数,除了传lambda表达式,kotlin还提供了其他方法,传递函数引用,函数引用可以把一个具名函数转换成一个值参,使用lambda表达式的地方,都可以使用函数引用。

fun main() {
    //通过::将具名函数转换成一个对象进行传递
    showStudentMsg("barry",2001,2021,::calStudentAge)
}

//将上面的匿名函数改造成一个具名函数
private fun calStudentAge(birYear:Int,year:Int) : Int{
    return year - birYear
}

private fun showStudentMsg(name:String,birYear:Int,year:Int,getStudentAge : (Int,Int)->Int){
    println("${name}同学${birYear}年出生,现在是${year}年")
    println("所以${name}同学今年${getStudentAge(birYear,year)}岁了")
}

kotlin中函数可以作为参数进行传递,实际上传递还是一个对象。也就是说函数在Kotlin 里可以作为对象存在。那我们如何让具名函数变成一个对象呢,其实就是通过::来实现的。只有在函数名前加上两个冒号,该函数才能变成一个对象进行传递。

在 Kotlin 里,一个函数名的前面加上两个冒号,它就不表示这个函数本身了,而表示一个对象,或者说一个指向对象的引用。

我们现在可以回到上面的一个问题,**为什么匿名函数可以赋值给变量,而正常函数不可以呢?**其实根据上面的讲述,大概也知道为什么了吧,现在我把之前的赋值代码换一下

fun main() {
    val a = add()  //这是函数调用,没有问题
    //val fun = add   //这是将函数赋值给fun这个变量,编译会报错
    val fun = ::add   //这是将一个函数类型的对象赋值给fun这个变量,没有问题
}

fun add() : Int{
    val b = 10
    val c = 20
    return b + c
}

匿名函数/lambda 可以赋值给变量或者作为参数进行传递,是因为kotlin中匿名函数其实不是真正意义上的「函数」,而是一个对象,一个函数类型的对象。它和加了::的具名函数是一个东西。

所以java中的lambda和kotlin中的lambda最大的区别就是,java中的lambda只是写法更加便捷,但并没有什么实质的变化。而kotlin中的lambda是实实在在的对象。

函数类型作为返回类型

既然kotlin中函数可以转变为一个对象,那么函数同样可以作为一个函数的返回类型

fun main() {
    val studentMsg = getStudentMsg()
    print(studentMsg("barry"))
}

//返回类型为函数的函数
fun getStudentMsg() : (String) -> String{
    //返回匿名函数,也就是返回一个函数类型的对象
    return {name:String->
        val age = 20
        "${name}同学今年${age}岁了"
    }
}

在main函数中,通过getStudentMsg()获取到一个类型为函数的对象,然后这个studentMsg("barry")这个操作其实是kotlin的一个语法糖,它等效于下面的代码:

studentMsg.invoke("barry")

所以这个studentMsg其实就是一个引用类型,指向了getStudentMsg()这个类型为函数的对象。

闭包

在kotlin中,匿名函数能修改并引用定义在自己的作用域之外的变量。匿名函数引用着定义自身的函数里的变量,一个函数引用着另一个函数声明的变量,这其实就是闭包。

像上面的代码可以改写成这样:

fun main() {
    val studentMsg = getStudentMsg()
    print(studentMsg("barry"))
}

//返回类型为函数的函数
fun getStudentMsg() : (String) -> String{
    //age变量是在getStudentMsg()函数里定义的
    val age = 20
    //返回匿名函数,也就是返回一个函数类型的对象
    return {name:String->
        //在匿名函数里我们引用了getStudentMsg()函数里的age变量
        "${name}同学今年${age}岁了"
    }
}

上面return后面跟着的{ ... }就是一个闭包

什么是闭包?

我们知道,变量分为全局变量和局部变量,全局变量,顾名思义,其作用域是当前文件甚至文件外的所有地方;而局部变量只能在其有限的作用域里获取。

那么,如何在外部调用局部变量呢?就是通过闭包,闭包就是能够读取其他函数内部变量的函数

那kotlin中使用闭包的意义在哪呢,为什么在Java中好像没怎么听过闭包这个概念?

Java其实也是有闭包的,一般会在匿名内部类才能体现出来,但Java中的闭包是一种有“残缺”的闭包,为什么这么说,可以看下下面这篇文章。

在上面编写kotlin代码中,可以发现和编写Java代码时有些不同。在Java中,我们在编写代码时,必须要有包(Package)和类(Class),就比如一个简单地输出Hello World,在Java中:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

而在kotlin中:

fun main(){
    println("Hello World")
}

那么Java中有包和类这两个东西,它会给我们带来作用域上的保护。我先拿kotlin举一个例子,比如我现在创建两个kotlin文件,然后在两个文件中都定义一个方法test,这是它就会报错

当然是用private修饰的话可以解决,但在Java中我创建两个Java文件,同样在两个文件中都定义一个方法test并用public进行修饰,是不会报错的。这是因为这两个Java文件虽然在同一个包下,但它们是不同的类,所以并不会影响。

Kotlin中也含有类,但Kotlin也有脚本语言的特性,所以它可以让我们不用使用类也能进行函数的使用,所以一旦使用到了脚本语言的特性,就可能会出现作用域的问题,同名变量或者函数就会产生冲突。所以kotlin中的闭包就是用来解决作用域这问题的。

lambda与匿名内部类

刚刚在上面也有提到一嘴,java中也有方法实现kotlin中传递函数这种类似的效果,通过接口来实现。现在我们用Java代码来复现一下

public class Test {

    public interface StudentAge{
        int getStudentAge(int birYear,int year);
    }

    public static void showStudentAge(String name,int birYear,int year,StudentAge studentAge){
        System.out.println(name + "同学" + birYear + "年出生,现在是" + year + "年");
        System.out.println("所以" + name + "同学今年" + studentAge.getStudentAge(birYear,year) + "岁了");
    }

    public static void main(String[] args) {
        showStudentAge("barry", 2001, 2021, new StudentAge() {
            @Override
            public int getStudentAge(int birYear, int year) {
                return year - birYear;
            }
        });
    }
}

上面在main函数中传递的最后一个参数就是一个匿名内部类,当然用java中的lambda表达式可以进一步的简化代码,如下

showStudentAge("barry", 2001, 2021, (birYear, year) -> year - birYear);

但java里面的lambda只是简化了书写,并没实质的改变,并不像kotlin中是可以实现一个函数类型的对象,在Java中必须借助接口才能实现kotlin中直接传递函数的效果。所以kotlin中的lambda还是要更加方便的。

本文转自 https://zhuanlan.zhihu.com/p/417635072,如有侵权,请联系删除。

在这里为了方便大家系统的学习Kotlin,这里特意联合了阿里P7架构师和谷歌技术团队共同整理了一份Kotlin全家桶学习资料,完整资料扫描下方二维码。

Kotlin入门教程指南,全家桶学习资料(含高级Kotlin强化和Kotlin协程入门进阶实战)

Kotlin 是一种新型的静态类型编程语言,有超过 60% 的专业 Android 开发者在使用,它有助于提高工作效率、开发者满意度和代码安全性。不仅可以减少常见代码错误,还可以轻松集成到现有应用中。

内容概要:Kotlin 入门教程指南、高级Kotlin强化实战和史上最详Android版kotlin协程入门进阶实战 。

内容特点:条理清晰,含图像化表示更加易懂。

由于文章内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要 Android中高级面试必知必会 完整文档的可扫描下方免费获取!

Kotlin入门教程指南

第一章 Kotlin 入门教程指南

​ ● 前言

img

第二章 概述

​ ● 使用 Kotlin 进行服务器端开发

​ ● 使用 Kotlin 进行 Android 开发

​ ● Kotlin JavaScript 概述

​ ● Kotlin/Native 用于原生开发

​ ● 用于异步编程等场景的协程

​ ● Kotlin 1.1 的新特性

​ ● Kotlin 1.2 的新特性

​ ● Kotlin 1.3 的新特性

img

第三章 开始

​ ● 基本语法

​ ● 习惯用法

​ ● 编码规范

img

第四章 基础

​ ● 基本类型

​ ● 包

​ ● 控制流:if、when、for、while

​ ● 返回和跳转

img

第五章 类与对象

​ ● 类与继承

​ ● 属性与字段

​ ● 接口

​ ● 可见性修饰符

​ ● 扩展

​ ● 数据类

​ ● 密封类

​ ● 泛型

​ ● 嵌套类与内部类

​ ● 枚举类

​ ● 对象表达式与对象声明

​ ● Inline classes

​ ● 委托

委托属性

img

第六章 函数与 Lambda 表达式

​ ● 函数

​ ● 高阶函数与 lambda 表达式

​ ● 内联函数

img

第七章 其他

​ ● 解构声明

​ ● 集合:List、Set、Map

​ ● 区间

​ ● 类型的检查与转换“is”与“as”

​ ● This 表达式

​ ● 相等性

​ ● 操作符重载

​ ● 空安全

​ ● 异常

​ ● 注解

​ ● 反射

​ ● 类型安全的构建器

​ ● 类型别名

​ ● 多平台程序设计

​ ● 关键字与操作符

img

第八章 Java 互操作与 JavaScript

​ ● 在 Kotlin 中调用 Java 代码

​ ● Java 中调用 Kotlin

​ ● JavaScript 动态类型

​ ● Kotlin 中调用 JavaScript

​ ● JavaScript 中调用 Kotlin

​ ● JavaScript 模块

​ ● JavaScript 反射

​ ● JavaScript DCE

img

第九章 协程

​ ● 协程基础

​ ● 取消与超时

​ ● 通道 (实验性的)

​ ● 组合挂起函数

​ ● 协程上下文与调度器

​ ● 异常处理

​ ● select 表达式(实验性的)

​ ● 共享的可变状态与并发

img

第十章 工具

​ ● 编写 Kotlin 代码文档

​ ● Kotlin 注解处理

​ ● 使用 Gradle

​ ● 使用 Maven

​ ● 使用 Ant

​ ● Kotlin 与 OSGi

​ ● 编译器插件

​ ● 不同组件的稳定性

img

第十一章 常见问题总结

​ ● FAQ

​ ● 与 Java 语言比较

​ ● 与 Scala 比较【官方已删除】

img

高级Kotlin强化实战

第一章 Kotlin 入门教程

​ ● Kotlin 概述

​ ● Kotlin 与 Java 比较

​ ● 巧用 Android Studio

​ ● 认识 Kotlin 基本类型

​ ● 走进 Kotlin 的数组

​ ● 走进 Kotlin 的集合

​ ● 完整代码

​ ● 基础语法

img

第二章 Kotlin 实战避坑指南

​ ● 方法入参是常量,不可修改

​ ● 不要 Companion、INSTANCE?

​ ● Java 重载,在 Kotlin 中怎么巧妙过渡一下?

​ ● Kotlin 中的判空姿势

​ ● Kotlin 复写 Java 父类中的方法

​ ● Kotlin “狠”起来,连TODO都不放过!

​ ● is、as` 中的坑

​ ● Kotlin 中的 Property 的理解

​ ● also 关键字

​ ● takeIf 关键字

​ ● 单例模式的写法

img

第三章 项目实战《Kotlin Jetpack 实战》

​ ● 从一个膜拜大神的 Demo 开始

​ ● Kotlin 写 Gradle 脚本是一种什么体验?

​ ● Kotlin 编程的三重境界

​ ● Kotlin 高阶函数

​ ● Kotlin 泛型

​ ● Kotlin 扩展

​ ● Kotlin 委托

​ ● 协程“不为人知”的调试技巧

​ ● 图解协程:suspend

img

史上最详Android版kotlin协程入门进阶实战

第一章 Kotlin协程的基础介绍

​ ● 协程是什么

​ ● 什么是Job 、Deferred 、协程作用域

​ ● Kotlin协程的基础用法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g14uGeVh-1678177930493)(https://docimg1.docs.qq.com/image/ME6Ygm_vFgAkpKvYo-TGIg.png?w=567&h=303)]

第二章 kotlin协程的关键知识点初步讲解

​ ● 协程调度器

​ ● 协程上下文

​ ● 协程启动模式

​ ● 协程作用域

​ ● 挂起函数

img

第三章 kotlin协程的异常处理

​ ● 协程异常的产生流程

​ ● 协程的异常处理

img

第四章 kotlin协程在Android中的基础应用

​ ● Android使用kotlin协程

​ ● 在Activity与Framgent中使用协程

​ ● ViewModel中使用协程

​ ● 其他环境下使用协程

第五章 kotlin协程的网络请求封装

​ ● 协程的常用环境

​ ● 协程在网络请求下的封装及使用

​ ● 高阶函数方式

​ ● 多状态函数返回值方式

img

第六章 深入kotlin协程原理(一)

​ ● suspend的花花肠子

​ ● 藏在身后的-Continuation

​ ● 村里的希望-SuspendLambda

img

第七章 深入kotlin协程原理(二)

​ ● 协程的那些小秘密

​ ● 协程的创建过程

​ ● 协程的挂起与恢复

​ ● 协程的执行与状态机

img

第八章 Kotlin Jetpack 实战

​ ● 从一个膜拜大神的 Demo 开始

​ ● Kotlin 写 Gradle 脚本是一种什么体验?

​ ● Kotlin 编程的三重境界

​ ● Kotlin 高阶函数

​ ● Kotlin 泛型

​ ● Kotlin 扩展

​ ● Kotlin 委托

​ ● 协程“不为人知”的调试技巧

​ ● 图解协程原理

img

第九章 Kotlin + 协程 + Retrofit + MVVM优雅的实现网络请求

​ ● 项目配置

​ ● 实现思路

​ ● 协程实现

​ ● 协程 + ViewModel + LiveData实现

​ ● 后续优化

​ ● 异常处理

​ ● 更新Retrofit 2.6.0

由于文章内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要 Android中高级面试必知必会 完整文档的可以扫描二维码获取)

更有更多资料,加微信免费领取

img

猜你喜欢

转载自blog.csdn.net/Misdirection_XG/article/details/129386830