From 8e973eb2e2aff65b338b603c1c2eff5a44b533ec Mon Sep 17 00:00:00 2001 From: tongtongstudio Date: Mon, 10 Nov 2025 20:30:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96livedata=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=80=92=E7=81=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dialer/livedata/SingleLiveEvent.java | 48 +++++++++++++++ .../ttstd/dialer/livedata/VersionedData.java | 22 +++++++ .../dialer/livedata/VersionedLiveData.java | 60 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 app/src/main/java/com/ttstd/dialer/livedata/SingleLiveEvent.java create mode 100644 app/src/main/java/com/ttstd/dialer/livedata/VersionedData.java create mode 100644 app/src/main/java/com/ttstd/dialer/livedata/VersionedLiveData.java diff --git a/app/src/main/java/com/ttstd/dialer/livedata/SingleLiveEvent.java b/app/src/main/java/com/ttstd/dialer/livedata/SingleLiveEvent.java new file mode 100644 index 0000000..dcf703d --- /dev/null +++ b/app/src/main/java/com/ttstd/dialer/livedata/SingleLiveEvent.java @@ -0,0 +1,48 @@ +package com.ttstd.dialer.livedata; + +import android.util.Log; + +import androidx.annotation.MainThread; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 解决一次性事件的数据倒灌问题,仅通知一次观察者 + */ +public class SingleLiveEvent extends MutableLiveData { + private static final String TAG = "SingleLiveEvent"; + private final AtomicBoolean mPending = new AtomicBoolean(false); // 标记事件是否待处理 + + @MainThread + @Override + public void observe(androidx.lifecycle.LifecycleOwner owner, final Observer observer) { + // 警告:多个观察者同时注册时,只有一个会收到通知 + if (hasActiveObservers()) { + Log.w(TAG, "多个观察者注册,但仅第一个会收到事件"); + } + + // 包装观察者,仅在事件未处理时触发 + super.observe(owner, t -> { + if (mPending.compareAndSet(true, false)) { // 原子操作:如果是true则改为false,并返回true + observer.onChanged(t); // 触发观察者回调 + } + }); + } + + @MainThread + @Override + public void setValue(T value) { + mPending.set(true); // 标记事件待处理 + super.setValue(value); + } + + /** + * 简化Void类型事件的调用(如无参数的事件) + */ + @MainThread + public void call() { + setValue(null); + } +} diff --git a/app/src/main/java/com/ttstd/dialer/livedata/VersionedData.java b/app/src/main/java/com/ttstd/dialer/livedata/VersionedData.java new file mode 100644 index 0000000..4a1f722 --- /dev/null +++ b/app/src/main/java/com/ttstd/dialer/livedata/VersionedData.java @@ -0,0 +1,22 @@ +package com.ttstd.dialer.livedata; + +/** + * 包装数据和版本号,用于版本校验 + */ +public class VersionedData { + private final T data; // 实际数据 + private final int version; // 数据版本号 + + public VersionedData(T data, int version) { + this.data = data; + this.version = version; + } + + public T getData() { + return data; + } + + public int getVersion() { + return version; + } +} diff --git a/app/src/main/java/com/ttstd/dialer/livedata/VersionedLiveData.java b/app/src/main/java/com/ttstd/dialer/livedata/VersionedLiveData.java new file mode 100644 index 0000000..bb8d32c --- /dev/null +++ b/app/src/main/java/com/ttstd/dialer/livedata/VersionedLiveData.java @@ -0,0 +1,60 @@ +package com.ttstd.dialer.livedata; + +import androidx.annotation.MainThread; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; + +/** + * 通过版本号控制数据消费,避免旧数据倒灌 + */ + +/** + * 带版本控制的LiveData,解决数据倒灌问题 + */ +public class VersionedLiveData extends LiveData> { + private int currentVersion; // 数据版本号(初始化为0) + + // 修正:父类构造器直接使用初始版本0,避免引用未初始化的currentVersion + public VersionedLiveData() { + super(new VersionedData<>(null, 0)); // 初始数据版本为0 + this.currentVersion = 0; // 初始化版本号(与父类初始数据一致) + } + + /** + * 修正:改名避免与父类setValue冲突(父类setValue参数为VersionedData) + * 更新数据并自动递增版本号 + */ + @MainThread + public void setNewValue(T newValue) { + currentVersion++; // 版本号递增 + // 调用父类的setValue,传入包装后的带版本数据 + super.setValue(new VersionedData<>(newValue, currentVersion)); + } + + /** + * 注册带版本校验的观察者,仅接收新版本数据 + */ + public void observeWithVersion(LifecycleOwner owner, final VersionedObserver observer) { + observe(owner, new Observer>() { + private int lastHandledVersion = -1; // 记录上次处理的版本号 + + @Override + public void onChanged(VersionedData newData) { + if (newData == null) return; + // 仅处理版本号高于上次的新数据 + if (newData.getVersion() > lastHandledVersion) { + lastHandledVersion = newData.getVersion(); + observer.onNewData(newData.getData()); + } + } + }); + } + + /** + * 版本化观察者接口,用于接收新数据 + */ + public interface VersionedObserver { + void onNewData(T data); + } +} \ No newline at end of file