note

val 是一个不能重新赋值的变量 var 则可以 kotlin的类型推断是在编译时确定的 不能对一个普通类型赋值为Null,但是在后面加问号则表示这个类型是nullable类型,即可以设置为null

var temp: String?

大括号,会返回最后的语句执行结果,可以直接赋值

val answerString: String = if(condition){
  "first line"
  "the condition is right !"
}else{
  "the condition is not right !"  
}

但是这样不够清晰,可以用when语句代替:

val answerString = when{
  count == 42 --> "i have the answer"
  count > 35 --> "the answer is close"  
  else -> "the answer eludes me"
}

方法可以直接被语句赋值:

fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
        "I have the answer"
    } else {
        "The answer eludes me"
    }

匿名方法:

val stringLengthFunc: (String) -> Int = { input ->
    input.length
}

高阶函数(higher order functions),允许方法参数:

//如果匿名方法是方法中的最后一个参数,可以把括号写在外面  
stringMapper("Android") { input ->
    input.length
}

类属性的默认访问权限是public

class Car{

}
val car = Car() //类的构造
class Car1(val wheels: List<Wheel>){
  var temp: Int = 15
    private set  //set访问权限控制    
}
val car = Car(...)

迁移kotlin: 1、兼容: 只需要创建一个新的kotlin文件,会有提示点击配置即可。 2、转化: 选中java文件 > 工具栏 > code > convert .. 转化只是从字节码层面等同,但是实际的结果代码还需自己优化(比如有些变量虽然没有声明时初始化,但是使用的时候肯定是有値的情况。kotlin会在声明时设置为nullable,而每次使用时解包装(unwrap))

//kotlin 路径配置
android {
   sourceSets {
       main.java.srcDirs += 'src/main/kotlin'
   }
}

在kotlin中,声明变量时必须初始化,否则使用lateinit关键字,比如最常见的view初始化

SAM可以缩写:

loginButton.setOnClickListener {
  //just handle logic
}

java的静态,用companon object{}关键字代替static:

class ProtocolAct : BlindBaseAct() {

    companion object {
        fun launch(context: Context) {

        }
        private const val TAG = "ff";//这里为什么和方法不一样,加一个const ?
    }
}

属性委托(delegation):https://developer.android.com/kotlin/common-patterns#delegate 这一段没用过,待后续再看

java本身是没有是否为空的严格类型的,所以kotlin调用java的类型时,可能出现无法判断是普通类型还是可空类型。!是一个适用此情况的平台类型,如String!,同时表示String和String? 当然如果加了@Nonnull注解,会被解析成String;@Nullable会被解析成String?

val account = Account("name")  //Account是java bean, 其中name 变量没有注解
val accountName = account.name!!.trim() // !!是非空断言,这样会让name作为非空String解析,可能异常
val safeAccountName = account.name?.trim()  //会自动判断name是否为空,不会有异常

对于null,有更为快速的Elvis运算符:

val name = account.name?.trim() ?: "default"

该运算符还可以用于更早的return:

fun smFunc(accont: Account?){
  accont ?: return
  doSomething()
}

初始化区域:

class A{
  val index: Int = 4
  //or
  val index: Int  
  init{
    index = 4
  }
}
val nullableFoo :Foo? = ...
//只在不为空的时候,传入方法并且执行
nullableFoo?.let { foo ->
   foo.baz()
   foo.zap()
}

协调器

coroutine 是一个并发设计模式。。 这里讲到需要放到子线程的不仅仅是网络请求和数据库操作(Dispatchers.IO -- disk or network), 甚至应该包括json解析,大列表循环(Dispatchers.Default -- CPU) 但是并没有给出具体的影响时间,只是说可能影响到jank就要。

主要是suspend 关键字,他不是回调,而是真正的阻塞协调器,在具体操作结束的时候再resume(这里需要看一发原理),这样一个明显好处是,不需要考虑回调方法所在的线程是否和调用方不一致。 而控制线程的方法是withContext(Dispatchers...), 它则对多次线程调用的创建做了优化,不会每次都创建;同样的对线程切换也有优化。(简单理解成一个线程池就是了。。)

制定协调器作用域(CoroutineScope)

主要用来控制coroutine的开始和取消,但是Dispatchers启动coroutine coroutine被取消的时候会产生一个CancellationException异常 如果一个协调器启动另一个协调器,那么他们有相同的作用域。 (viewModelScope)

启动

launch 不会返回值 async 会返回值,配合await/awaitAll(async会在某个时间调用await,相应的会把异常传递给await,这样就有可能无法在日志中获取异常信息)

如果在调用async的方法返回前不调用await方法,那么coroutine会在操作执行完之后才停止

架构组建库,scope地址: https://developer.android.com/topic/libraries/architecture/coroutines

kotlin和java交互指南

kotlin调用java

java中需要注意的 1、不能有kotlin的 hard keywords,不然需要倒引号来转义 2、除非必须,否则禁止使用Any的拓展方法或者拓展属性的名字,因为同名的成员或者域名会覆盖Any的。 3、公用部分的参数、返回等一定要添加nullability注解,否则会被解释成! 4、SAM参数最好放在最后,可以简略书写 5、getter,setter标准写成:getPro,setPro,isPro 6、方法命名不要和操作符重载方法的名称相同

java调用kotlin

1、当一个文件包含一个顶级(top-level)方法或属性,使用@file:JvmName("Foo")来定义一个好名字,否则会被解释成MyClassKt;@file:JvmMultifileClass合并多个 2、这部分需要看完kotlin语言再说。。。 https://developer.android.com/kotlin/interop#kotlin_for_java_consumption

风格指南

Last updated

Was this helpful?