livedata+ lambda遇到的坑

news/2025/1/16 0:53:57/

首先抛出个异常

FATAL EXCEPTION: main

Process: com.lion.media, PID: 5513

java.lang.IllegalArgumentException: Cannot add the same observer with different lifecycles

at androidx.lifecycle.LiveData.observe(LiveData.java:199)

这是在livedata.observe(this) {

// ...

}触发的异常

下面分析下

从源码看,试图将observer在两个lifecycle注册到livedata就会触发这个异常,正常情况下很难遇到这个问题,但是有些情况容易出现问题:

前提:livedata的生命周期比和订阅这个livedata页面长

  1. 页面没有正常销毁,又创建一次

  1. 两个页面用同一个类,比如Fragment, 这个fragment里订阅livedata

反编译发现:

如果lambda内没有引用外部非静态成员,会被编译程类似单例的类

livedata.observe((LifecycleOwner)this, -$$Lambda$RadioCatalogFragment$caW7Hi16aKYOCUVWVHqIazPGd8s.INSTANCE);

一般情况是new出来的

livedata.observe((LifecycleOwner)this, new -$$Lambda$RadioCatalogFragment$aQGE2mZtdMX-nI-7aVkDUov6kPw(this))

如何解决:

  1. 不要使用lambda,改用object

  1. lambda内引用外部非静态变量或方法

另外网传一种方案:

class SafeMutableLiveData<T>: MutableLiveData<T>() {

private var weakLifecycleOwner: WeakReference<LifecycleOwner>? = null

override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {

weakLifecycleOwner?.get()?.let {

removeObservers(it)

}

weakLifecycleOwner = WeakReference(owner)

super.observe(owner, observer)

}

override fun setValue(value: T) {

try {

super.setValue(value)

} catch (e: Exception) {

super.postValue(value)

}

}

}

这种方案不可取,原因是如果这个livedata有很多个页面都要订阅时,就错误了,setValue方法到不错,可用


http://www.ppmy.cn/news/20456.html

相关文章

Java:基于注解的Spring使用【AOP容器】

目录 第十五章 AOP前奏15.1 代理模式15.2 为什么需要代理【程序中】15.3 手动实现动态代理环境搭建15.4 手动实现动态代理关键步骤第十六章 Spring中AOP【重点】16.1 AspectJ框架【AOP框架】16.2 使用AspectJ步骤&#xff08;入门&#xff09;16.3 Spring中AOP概述16.4 Spring中…

Linux基础IO+文件fd

1&#xff1a;文件理解文件内容属性&#xff0c;因此空文件在磁盘上也占用空间。文件用路径名文件名作为标识文件的唯一性。对文件的操作&#xff0c;就是对文件的内容属性的操作。在linux中&#xff0c;如果没有指定文件路径&#xff0c;默认在当前路径下执行操作。总结&#…

再见 Matplotlib 和 Seaborn ,Python 画图建议用这个

本文主要介绍 Python 中用来替代 Matplotlib 和 Seaborn 的可视化工具 plotly&#xff0c;并结合实例讲解了 plotly 的优点和用法&#xff0c;满足了可视化绘图的交互需求。 数据可视化是人脑有效理解各种信息的最舒适、最直观的方式。对于需要处理数据的人来说&#xff0c;能…

LabVIEW 在NI Linux实时设备上访问Shell

LabVIEW 在NI Linux实时设备上访问Shell有一台运行NI Linux实时操作系统的设备&#xff0c;想访问设备上的shell或终端。要使用以下任一方法与设备通信&#xff0c;必须在计算机上安装终端客户端。使用SSH连接&#xff1a;1. 打开电源并将设备连接到网络或直接连接到计算机。2.…

20篇高质量程序人生文章分享,做开发不仅仅只有代码

我一直觉得&#xff0c;我们做开发&#xff0c;不应该只有代码&#xff0c;合上公司的电脑脱离了公司的产品需求就脱离了程序&#xff0c;而应该结合软件的程序思维去更多的思考我们所处的生活和空间&#xff0c;从而指导自己面对更多的未曾见过的人与事&#xff0c;这可能就是…

双向链表实现简单的增删查改

前言&#xff1a;上次分享了单向链表的增删查改&#xff0c;这次要介绍双向链表的增删查改&#xff0c;其实双向链表也有多种&#xff0c;这次主要介绍结构最复杂但是实现起功能反而最简单的带头双向循环链表&#xff0c;希望我的分享对各位有些许帮助。学习这篇文章的内容最好…

算法训练营DAY45|322. 零钱兑换、279.完全平方数

两道题思路上有相似之处&#xff0c;都是求得最少的种类方法&#xff0c;也就是说在完全背包里给定容量时&#xff0c;用最少的物品去装满背包。它和用最多的方法去装满背包也有一些相似&#xff0c;也就是说两者实际上是互通的。 322. 零钱兑换 - 力扣&#xff08;LeetCode&a…

C++ —— 容器适配器和仿函数

目录 1.什么是容器适配器 2.stack的模拟实现 3.queue的模拟实现 4.deque概述 5.priority_queue的模拟实现 5.1仿函数 5.2模拟实现 6.反向迭代器 1.什么是容器适配器 在已有的容器(vector、list)的基础上适配出其他的容器。就类似于手机、笔记本电脑的电源适配器&…