是否可以防止LiveData在开始观察时接收最后一个值?我正在考虑将LiveData用作事件。
例如,类似于显示消息,导航事件或对话框触发器的事件,类似于EventBus。
与ViewModel
和片段之间的通信有关的问题,Google向我们LiveData
提供了用数据更新视图的方法,但是这种类型的通信方式不适合我们只需要通过单个事件更新一次视图,也无法举行视图在ViewModel
中的引用,并调用一些方法,因为这会导致内存泄漏。
[我发现了类似的SingleLiveEvent-但它仅适用于1个观察者,不适用于多个观察者。
class LiveDataItem {
long mRealtimeNanos;
YOUR_PREVIOUS_LIVEDATA_TYPE mData;
LiveDataItem(YOUR_PREVIOUS_LIVEDATA_TYPE data, long realtimeNanos) {
this.mRealtimeNanos = realtimeNanos;
this.mData = data;
}
}
然后我创建了一个新的“全局”变量:
final List<Long> mExcludedRealtimeNanos = new ArrayList<>;
此时,我选择通过新的自定义“ postValue()”方法设置“ LiveDataItem”类型的“ set / postValue()”,而不是原始的“ YOUR_PREVIOUS_LIVEDATA_TYPE”类型:
public void myPostValue(YOUR_PREVIOUS_LIVEDATA_TYPE data, boolean notifyWhenObserved) {
long cRealtimeNanos = SystemClock.realtimeNanos();
if (!notifyWhenObserved) mExcludedRealtimeNanos.add(cRealtimeNanos);
....postValue(new LiveDataItem(data, cRealtimeNanos));
}
然后我创建了一个普通的观察器,它将接收所有“ Changed()”事件,并在其中放入有关“ RealtimeNanos”的检查:
public void onChanged(LiveDataItem myDataItem) {
boolean cFound = false;
for (Long cRealtimeNanos : mExcludedRealtimeNanos) {
if (cRealtimeNanos == myDataItem.mRealtimeNanos) {
cFound = true;
break;
}
}
//check if it was found --> NO: it means that I wish to get the notification
if (!cFound) mMyOnChangedCallback(myDataItem.mData)
}
显然,“ mMyOnChangedCallback()”方法是一个回调函数,只有当您设置在数据创建期间通知它时,才会在原始“ onChanged()”事件引发时调用该函数。
您可以选择仅通过从“ mExcludedRealtimeNanos”中删除THAT RealtimeNanos,然后将新的Observer附加到该LiveData来再次收到通知。几乎没有什么更改可以改进此代码,但是我写了一些我对旧代码的记忆(目前我不在电脑旁)。例如,当使用自定义postValue()方法发布新数据时,我们可以决定从“ mExcludedRealtimeNanos”中删除一个值。...
ViewModel
class在ViewModel中:
/** expose Save LiveData Event */ public void newSaveEvent() { saveEvent.setValue(new Event<>(true)); } private final MutableLiveData<Event<Boolean>> saveEvent = new MutableLiveData<>(); LiveData<Event<Boolean>> onSaveEvent() { return saveEvent; }
活动/片段中
mViewModel
.onSaveEvent()
.observe(
getViewLifecycleOwner(),
booleanEvent -> {
if (booleanEvent != null)
final Boolean shouldSave = booleanEvent.getContentIfNotHandled();
if (shouldSave != null && shouldSave) saveData();
}
});
val liveData = MutableLiveData<String>()
liveData.value = "Hello"
val freshResult = mutableListOf<String>()
val normalResult = mutableListOf<String>()
liveData.observeForeverFreshly(Observer {
freshResult.add(it)
})
liveData.observeForever(Observer {
normalResult.add(it)
})
liveData.value = "World"
assertEquals(listOf("World"), freshResult)
assertEquals(listOf("Hello", "World"), normalResult)
基本源代码解释为简明。 有关更多详细信息(以支持某些特殊情况,例如从Transformations.map返回的MediatorLiveData
,您可以在github中查看它:livedata-ext
FreshLiveData.kt
fun <T> LiveData<T>.observeFreshly(owner: LifecycleOwner, observer: Observer<in T>) { // extention fuction to get LiveData's version, will explain in below. val sinceVersion = this.version() this.observe(owner, FreshObserver<T>(observer, this, sinceVersion)) } fun <T> LiveData<T>.observeForeverFreshly(observer: Observer<in T>, skipPendingValue: Boolean = true) { val sinceVersion = this.version() this.observeForever(FreshObserver<T>(observer, this, sinceVersion)) } // Removes the observer which has been previously observed by [observeFreshly] or [observeForeverFreshly]. fun <T> LiveData<T>.removeObserverFreshly(observer: Observer<in T>) { this.removeObserver(FreshObserver<T>(observer, this, 0)) } class FreshObserver<T>( private val delegate: Observer<in T>, private val liveData: LiveData<*>, private val sinceVersion: Int ) : Observer<T> { override fun onChanged(t: T) { if (liveData.version() > sinceVersion) { delegate.onChanged(t) } } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as FreshObserver<*> if (delegate != other.delegate) return false return true } override fun hashCode(): Int { return delegate.hashCode() } }
因为我们需要访问LiveData的pcakage可见方法
getVersion()
进行比较,所以请在包android.arch.lifecycle
或androidx.lifecycle
(AndroidX)中创建一个类:
LiveDataHiddenApi.kt
package androidx.lifecycle
fun LiveData<*>.version(): Int {
return this.getVersion()
}