Kotlin 使用 Livedata 问题汇总

255 阅读1分钟

IllegalArgumentException

总结

使用 lambda + livedata 时,lambda 对象有可能单例,导致多次 observe() 方法报错

现象

从 observe() 源码可以看出它是由于一个 observer 监听了多个 lifecycle。正常情况下不会出现,但如果使用了 kotlin 的 lambda 表达式就有可能出现。

image.png

原因

kotlin 中的 lambda 最终都会转换成一个对象,一般情况下每一次使用 lambda 都会生成不同的对象,但如果该类不依赖某个具体对象,kotlin 就使用单例模式实现该类,从而每一个 lambda 都是同一个对象。比如对下面的方法


liveData.observe(this@MainActivity){
    // 什么都不做
    // 或者直接使用 log 输出一个固定字符串
    // 两者效果一样
}

liveData.observe(this@MainActivity){
    // testStr 是 MainActivity 中的一个成员变量
    Log.e(TAG, testStr)
}

看一下第一个 observe() 对应的 smali 代码

// MainActivity$$ExternalSyntheticLambda2 就是第一个 lambda 对应的类
// 这里直接读取 INSTANCE 字段
sget-object v2, Lcom/example/demo/MainActivity$$ExternalSyntheticLambda2;->INSTANCE:Lcom/example/demo/MainActivity$$ExternalSyntheticLambda2;

看一下 ExternalSyntheticLambda2 的主要逻辑

6CD71FEF-F369-4BED-959A-A3B5E37D66E5.png

可以看出空 lambda 对象就是单例的

第二个 observer 对应的 smali 如下,可以看到是标准的 new 对象流程,所以不会存在多次 observe() 时 observer() 相同的情况。

    // 标准的构建对象指令
    
    new-instance v2, Lcom/example/demo/MainActivity$$ExternalSyntheticLambda1;

    invoke-direct {v2, p0}, Lcom/example/demo/MainActivity$$ExternalSyntheticLambda1;-><init>(Lcom/example/demo/MainActivity;)V