懒加载

lateinit

懒加载,则用于只能生命周期流程中进行获取或者初始化的变量,比如 Android 的 onCreate(),修饰var

lazy函数
1
    public fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)

使用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 //得到lazy对象
val init = lazy(LazyThreadSafetyMode.SYNCHRONIZED) { TextView(this).apply {
    textSize = sp(10f).toFloat()
    textColor = Color.BLUE}
 }

//或者 不设置参数
val init = lazy { TextView(this).apply {
    textSize = sp(10f).toFloat()
    textColor = Color.BLUE}
 }

懒加载,与by经常一起使用,修饰val


by 委托模式

Kotlin中,委托的实现依靠于关键字by表示将抽象主题的实例(by后边的实例)保存在代理类实例的内部

定义语法:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    val/var <property name>: <Type> by <expression>
    比如:  val a:Int by lazy {2}
    比如:
    interface ISports {
        fun doSports()
    }

    class SwimForSports: ISports{
        override fun doSports() {
            println("do swim")
        }
    }

    class SportsManager(sport: ISports): ISports by sport

    fun main(args: Array<String>) {
        val swimSports: SwimForSports = SwimForSports()
        SportsManager(swimSports).doSports()// Log:do swim
    }        
  • var/val:属性类型(可变/只读)
  • name:属性名称
  • Type:属性的数据类型
  • expression:代理类
可观察属性(Observable)与Vetoable
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var name: String by Delegates.observable("wang", {
    kProperty, oldName, newName ->
    println("kProperty:${kProperty.name} | oldName:$oldName | newName:$newName")
})

fun main(args: Array<String>) {

    println("name: $name") // Log:nam:wang

    name = "zhang" // Log:kProperty:name | oldName:wang | newName:zhang

    name = "li" // Log:kProperty:name | oldName:zhang | newName:li
}    

区别是Vetoable会有返回值,如果返回值是true,才允许赋值

Not Null
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class App : Application() {
    companion object {
        var instance: App by Delegates.notNull()
    } 

    override fun onCreate() {
        super.onCreate()
        instance = this
    }
}
将多个属性保存在一个map内
1
2
3
4
class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int by map
}
自定义委托模式 可参考Observable或者与Vetoable

ReadOnlyProperty接口主要用于实现只读属性的属性委托。

ReadWriteProperty接口主要用于实现可变属性的属性委托。

创建一个委托类SingleValueVar,继承自ReadWriteProperty

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class SingleValueVar<T> : ReadWriteProperty<Any?, T> {

    private var value: T? = null

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        if (null != value && null == this.value) {
            this.value = value // 只允许了初次修改
        }
    }

    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return value!!
    }
}
为属性设置委托
1
2
3
4
5
6
7
class Student {
    var no: Int by SingleValueVar<Int>()
    var name: String = "wang"
    override fun toString(): String {
        return "no: $no | name: $name"
    }
}

##### 测试实例 fun main(args: Array) { var stu: Student = Student()

1
2
3
4
5
6
7
8
9
    stu.no = 20
    stu.name = "wang"

    println(stu.toString()) // 打印:no: 20 | name: wang

    stu.no = 30
    stu.name = "li"
    println(stu.toString()) // 打印:no: 20 | name: li
}

高阶函数

let函数

1
2
3
4
5
6
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

适用于处理不为null的操作场景

### also函数

1
2
3
4
5
6
7
 public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

适用于let函数的任何场景,一般可用于多个扩展函数链式调用

with函数

不是拓展函数

1
2
3
4
5
6
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上

### run函数

1
2
3
4
5
6
 public inline fun <R> run(block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

适用于let,with函数任何场景。

apply函数

1
2
3
4
5
6
7
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}
  • 适用于run函数的任何场景,一般用于初始化一个对象实例的时候,操作对象属性,并最终返回这个对象。
  • 动态inflate出一个XML的View的时候需要给View绑定数据也会用到.
  • 一般可用于多个扩展函数链式调用
  • 数据model多层级包裹判空处理的问题