局部属性
var i by local { 0 }
Button {
TextFlatten(Modifier.padding(7.scaled)) { "counter: $i".emit() }
}.clickable { i++ }
这段代码生成了一个按钮,每次点击它,显示的数值就会+1。
关于kotlin属性委托语法:link
用法
以下写法如果没有被idea自动处理import,把鼠标点在by上并按Alt+Enter。
var a by local { 3 }
val b by local(customId) { "alice" }
var c by local.animatable { 20.0 }
val size by local.autoAnimate { if(expanded) 50.px else 25.px }
val data by stable { loadData() }
var count by static { 0 }
// ...
local{}是local.property{}的简写。property{}为普通变量,animatable{}和autoAnimate{}是动画变量,cached(key){}为缓存变量。
local,stable,static表示变量的生命周期。
指定id
一般情况下不需要指定id。使用前述的语法即可。
默认使用的追加id为传入lambda对象的::class。可以手动传入指定的id。
local和stable变量存在每个Screen单独管理的map中。存储key为当前context的id后追加上传入的id。正常情况下每个变量应该有一个固定且唯一的id。
static变量存储在一张全局共享的map中。使用的key与context的id无关。
与普通val的区别
var a = 0
var b by local { 0 }
// ...
.clickable {
a++
b++
}
在ui中会发现a的值始终是0,而b的值随着点击自增。
只要你想让这个值像一个稳定的变量,反复读写它的值,那就应该使用 by remember()
生命周期
local
一段ui代码如果在某帧内没有被执行,其中的local属性会全部被销毁。下次执行到此处时会重新调用lambda的内容来创建这个变量。
stable
stable属性的存活时间为首次创建到Screen销毁。延长了生命周期,可以使得用户切换页面再切回后依然保留之前的状态。这意味着其中的内存不会自动销毁,管理不当会造成泄露。如果不能确保不泄露,应优先使用local。
static
static属性是全局共享的,效果类似全局变量或static变量。如果有需要用static.property(id) { value }的方式手动指定id,会使得具有相同id的声明指向同一属性(包括其它mod中的声明)。所以尽量指定不会重复的id,除非有意使用这种方式与其它mod通信。
动画
animatable和autoAnimate能自动给可以插值的变量插值。它们都可以指定插值函数和时长。
animatable
var height by animatable(10.px)
//...
.clickable { height = 30.px }
点击后,读取height的值,会发现读到的值从10随着时间平滑变化到30。
autoAnimate
和前者类似,但是只能委托给只读属性,用法略有不同。
val height by autoAnimate { if(bl) width else 30.px }
缓存
使用cached可以缓存一个计算开销较大的值。普通的加减乘除不建议使用。
val result by cached(key) {
// compute...
}
对于计算耗时更长的值,建议使用协程调度到其它线程来执行,并缓存结果。
val deferred by local {
async(Dispatchers.IO) {
// ...
}
}
if(deferred.isCompleted) {
// ...
}
或者
var result by local<A?> { null }
local {
launch(Dispatchers.IO) {
// ...
result = xxx
}
}
对属性进行多线程读写是可以接受的,因为map读写在local{}中已经完成,后续过程中不进行map读写。