LiveData 防止在开始观察时收到最后一个值
Posted
技术标签:
【中文标题】LiveData 防止在开始观察时收到最后一个值【英文标题】:LiveData prevent receive the last value when start observing 【发布时间】:2018-09-24 17:53:42 【问题描述】:是否可以防止LiveData
在开始观察时收到最后一个值?
我正在考虑使用LiveData
作为事件。
例如显示消息、导航事件或对话触发器等事件,类似于EventBus
。
ViewModel
和 Fragment 之间的通信问题,Google 给了我们LiveData
用数据更新视图,但是这种类型的通信不适合我们只需要用单个事件更新视图一次,我们也不能在ViewModel
中保留视图的引用并调用一些方法,因为它会造成内存泄漏。
我发现了类似的 SingleLiveEvent - 但它仅适用于 1 个观察者,而不适用于多个观察者。
---更新----
正如@EpicPandaForce 所说“没有理由将 LiveData 用作它不是的东西”,问题的意图可能是Communication between view and ViewModel in MVVM with LiveData
【问题讨论】:
嗨,你能澄清你问题中的第二句话吗?你到底想达到什么目标? 消息、导航事件或对话触发器等事件。类似于 EventBus 我一直在为同样的问题苦苦挣扎,但我终其一生都找不到关于它的好信息。我真的很高兴看到其他人也遇到过它。无论如何,我可能已经能够制定出一个非常干净的解决方案。准备好后我会发布它作为答案。 @d4vidi 希望看到解决方案 我成功使用github.com/hadilq/LiveEvent库。 【参考方案1】:我在 MutableLiveData 中使用 Google 示例中的这个 EventWraper 类
/**
* Used as a wrapper for data that is exposed via a LiveData that represents an event.
*/
public class Event<T>
private T mContent;
private boolean hasBeenHandled = false;
public Event( T content)
if (content == null)
throw new IllegalArgumentException("null values in Event are not allowed.");
mContent = content;
@Nullable
public T getContentIfNotHandled()
if (hasBeenHandled)
return null;
else
hasBeenHandled = true;
return mContent;
public boolean hasBeenHandled()
return hasBeenHandled;
在 ViewModel 中:
/** expose Save LiveData Event */
public void newSaveEvent()
saveEvent.setValue(new Event<>(true));
private final MutableLiveData<Event<Boolean>> saveEvent = new MutableLiveData<>();
public LiveData<Event<Boolean>> onSaveEvent()
return saveEvent;
在活动/片段中
mViewModel
.onSaveEvent()
.observe(
getViewLifecycleOwner(),
booleanEvent ->
if (booleanEvent != null)
final Boolean shouldSave = booleanEvent.getContentIfNotHandled();
if (shouldSave != null && shouldSave) saveData();
);
【讨论】:
【参考方案2】:面对同样的问题,我创建了一些简单的kotlin扩展函数,可以轻松解决问题。
用法如下:
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)
基本源码解释为bllow。
更多细节(支持一些特殊情况,例如从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
if (delegate != (other as FreshObserver<*>).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()
【讨论】:
【参考方案3】:拥有一些 RxJava 经验,我已经习惯于认为这种行为要求通常是 Observeable
(在我们的例子中为 LiveData
)所关心的问题。有许多operators,例如replay(),可以控制与用户实际发布的内容相比实际发布的内容(以及何时发布)。本质上,SingleLiveEvent
也有相同的概念。
因此,我提出了 MutableLiveData
的修改后实现,称为 VolatileLiveData
:
open class VolatileLiveData<T> : MutableLiveData<T>()
private val lastValueSeq = AtomicInteger(0)
private val wrappers = HashMap<Observer<in T>, Observer<T>>()
@MainThread
public override fun setValue(value: T)
lastValueSeq.incrementAndGet()
super.setValue(value)
@MainThread
public override fun observe(owner: LifecycleOwner, observer: Observer<in T>)
val observerWrapper = ObserverWrapper(lastValueSeq, observer)
wrappers[observer] = observerWrapper
super.observe(owner, observerWrapper)
@MainThread
public override fun observeForever(observer: Observer<in T>)
val observerWrapper = ObserverWrapper(lastValueSeq, observer)
wrappers[observer] = observerWrapper
super.observeForever(observerWrapper)
@MainThread
public override fun removeObserver(observer: Observer<in T>)
val observerWrapper = wrappers[observer]
observerWrapper?.let
wrappers.remove(observerWrapper)
super.removeObserver(observerWrapper)
private class ObserverWrapper<T>(private var currentSeq: AtomicInteger, private val observer: Observer<in T>) : Observer<T>
private val initialSeq = currentSeq.get()
private var _observer: Observer<in T> = Observer
if (currentSeq.get() != initialSeq)
// Optimization: this wrapper implementation is only needed in the beginning.
// Once a valid call is made (i.e. with a different concurrent sequence), we
// get rid of it any apply the real implementation as a direct callthrough.
_observer = observer
_observer.onChanged(it)
override fun onChanged(value: T)
_observer.onChanged(value)
首先,与@emandt 类似,我将唯一的序列与每个实时值相关联——但严格在实时数据本身的范围内。只要将值设置为实时数据,就会设置此序列。
其次,受SingleLiveData
的启发,我在用户的观察者周围引入了包装器,只有在序列不同时才调用它(即在订阅后设置了 new 值)。
这基本上总结了它,但完整的文档,请转到我的gist。
用法
至于使用它 - 如果您可以完全控制 LiveData
,只需像使用 MutableLiveData
一样使用 VolatileLiveData
。如果数据最初来自其他地方(例如 Room),则可以使用 Transformations.switchMap()
来“切换”到 volatile 实现。
【讨论】:
【参考方案4】:我创建了一个新的类来保存我的真实数据和一个“特殊 ID”:
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()”方法来“设置/postValue()”我的“LiveDataItem”类型,而不是原来的“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));
然后我创建了一个普通的 Observer,它将接收所有“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”中删除那个 RealtimeNanos,然后将一个新的观察者附加到那个 LiveData。
很少有更改可以改进此代码,但我给您写了我记得的旧代码(我目前不在电脑旁)。例如,当使用我们的自定义 postValue() 方法发布新数据时,我们可以决定从“mExcludedRealtimeNanos”中删除一个值......
【讨论】:
是的,我考虑为每个事件提供唯一 ID,好主意我会检查它,谢谢。【参考方案5】:如果您按原样使用它们,我认为在开始观察时无法阻止 LiveData 接收最后一个值。您可以做的是扩展ViewModel
class,使其仅在添加观察者时通知视图。
另一种选择是简单地忽略回调。
向 ViewModel 添加一个标志。
private boolean isFirstTime = true;
public boolean isFirstTime() return isFirstTime;
public boolean onObserverAdded() isFirstTime = false; `
在回调中添加检查
@Override
public void onChanged(@Nullable final String newName)
boolean ignore = ((MyViewModel)ViewModelProviders.of(MyActivity.this).get(MyViewModel.class)).isFirstTime();
if(ignore) return;
// Update the UI
添加观察者后最后调用onObserverAdded()
。
【讨论】:
【参考方案6】:根据jurij-pitulja的回答。
如果我们使用kotlin coroutines
,解决方案如下所示。
class Event<T>(private val content: T)
var isHandled = false
private set
fun getContentIfNotHandled(): T?
return takeIf !isHandled ?.let
isHandled = true
content
在view model
类内部将Flow.asLiveData()
替换为emit new Event
val authResult: LiveData<Event<Result<AuthResponse>>> = _emailLiveData.switchMap email ->
liveData
repository.authRequest(email).collect
emit(Event(it))
在fragment
内部实现observer
方法
viewModel.authResult.observe(viewLifecycleOwner)
it.getContentIfNotHandled()?.run
onAuthRequestComplete(this)
【讨论】:
【参考方案7】:我创建了一个 LiveData 对象FreshLiveData
,它仅在调用setValue
或postValue
后才向观察者发出onChange
。
FreshLiveData.kt
/**
* A lifecycle-aware observable that emits only new data after subscription. Any data that has
* already been set, before the observable has subscribed, will be ignored.
*
* This avoids a common problem with events: on configuration change (like rotation, font change) an
* update can be emitted if the observer is active. This LiveData only calls the observable if
* there's an explicit call to setValue() or postValue().
*
* All observers will be notified of change(s).
*/
class FreshLiveData<T> : MutableLiveData<T>()
private val observers = mutableMapOf<LifecycleOwner, FreshLiveDataObserver>()
override fun observe(owner: LifecycleOwner, observer: Observer<in T>)
@Suppress("UNCHECKED_CAST")
observer as Observer<T>
observers[owner].apply
if (this == null)
observers[owner] = FreshLiveDataObserver(observer).apply
super.observe(owner, this)
else
add(observer)
override fun observeForever(observer: Observer<in T>)
@Suppress("UNCHECKED_CAST")
observer as Observer<T>
observers[ProcessLifecycleOwner.get()].apply
if (this == null)
observers[ProcessLifecycleOwner.get()] = FreshLiveDataObserver(observer).apply
super.observeForever(this)
else
add(observer)
override fun removeObservers(owner: LifecycleOwner)
observers.remove(owner)
super.removeObservers(owner)
override fun removeObserver(observer: Observer<in T>)
@Suppress("UNCHECKED_CAST")
observers.forEach it.value.remove(observer as Observer<T>)
super.removeObserver(observer)
@MainThread
override fun setValue(t: T?)
observers.forEach it.value.setPending()
super.setValue(t)
override fun postValue(value: T)
observers.forEach it.value.setPending()
super.postValue(value)
inner class FreshLiveDataObserver(observer: Observer<T>) : Observer<T>
private val observers = mutableSetOf<Observer<T>>()
private val pending = AtomicBoolean(false)
init
observers.add(observer)
fun add(observer: Observer<T>) = observers.add(observer)
fun remove(observer: Observer<T>) = observers.remove(observer)
fun setPending() = pending.set(true)
override fun onChanged(t: T)
if (pending.compareAndSet(true, false))
observers.forEach observer ->
observer.onChanged(t)
这是一个将现有LiveData
转换为FreshLiveData
的扩展。
LiveDataExtensions.kt
@MainThread
fun <T> LiveData<T>.toFreshLiveData(): LiveData<T>
val freshLiveData = FreshLiveData<T>()
val output = MediatorLiveData<T>()
// push any onChange from the LiveData to the FreshLiveData
output.addSource(this) liveDataValue -> freshLiveData.value = liveDataValue
// then push any onChange from the FreshLiveData out
output.addSource(freshLiveData) freshLiveDataValue -> output.value = freshLiveDataValue
return output
用法:
val liveData = MutableLiveData<Boolean>()
liveData.value = false
liveData.toFreshLiveData().observeForever
// won't get called with `it = false` because the observe was setup after setting that livedata value
// will get called with `it = true` because the observer was setup before setting that livedata value
liveData.value = false
val freshLiveData = FreshLiveData<Boolean>()
freshLiveData.value = false
freshLiveData.observeForever
// won't get called with `it = false` because the observe was setup after setting that livedata value
// will get called with `it = true` because the observer was setup before setting that livedata value
freshLiveData.value = true
【讨论】:
【参考方案8】:没有理由使用 LiveData,因为它不是。如果您需要一个单独的行为(不保留先前值的东西),那么您应该使用不保留先前值的组件 - 而不是围绕它进行修改(“记住”它已经发出然后忘记发射等)
虽然没有其他正确的解决方案可用,所以我最终不得不自己写一个,所以我没有推荐的替代方案,我不得不推荐我为这个特定目的写的那个。
无论如何,你可以添加live-event
库:
implementation 'com.github.Zhuinden:live-event:1.2.0'
来自 Jitpack:maven url "https://jitpack.io"
那你就可以了
private val eventEmitter = EventEmitter<WordController.Events>()
val controllerEvents: EventSource<WordController.Events> = eventEmitter
和
controllerEvents.observe(viewLifecycleOwner) event: WordController.Events ->
when (event)
is WordController.Events.NewWordAdded -> showToast("Added $event.word")
.safe()
【讨论】:
使用这个库超出了主要问题的目的/范围。作者要求为 LiveData 提供解决方案,而不是通用的解决方法/解决方案来达到他的成就。 LiveData 不是设计出来的,不适合这个。其他都是骗人的。 它怎么可能不是为这样一个简单的用例而设计的呢?例如:ViewModel 需要通知 View 发生错误,然后 View 显示 SnackBar。然后再次开始观察该观察者(活动重新启动),您会收到错误消息。对于这个用例,我还需要一些解决方法或技巧吗?对我来说最简单的解决方法是 RxJava。 @Nikola LiveData 像 BehaviorRelay 一样工作,它总是会发出最后一个发出的值。如果您需要 PublishRelay,那么 LiveData 将不是一个合适的解决方案。 “官方 Google 示例”使用EventObserver
+ LiveData<Event<T>>
,但实际上这只是 SingleLiveData
有更多代码,这已经像 BehaviorRelay.skip(1)
这很尴尬。
如果不引入一些 hack 或对抗框架,LiveData 无法解决此问题。 @EpicPandaForce 介绍的库很简单,经过良好测试,最重要的是,为我解决了手头的问题。【参考方案9】:
即使我也有同样的要求。我通过扩展 MutableLiveData 实现了这一点
package com.idroidz.android.ion.util;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
import java.util.concurrent.atomic.AtomicBoolean;
public class VolatileMutableLiveData<T> extends MutableLiveData<T>
private final AtomicBoolean mPending = new AtomicBoolean(false);
@MainThread
public void observe(LifecycleOwner owner, final Observer<T> observer)
// Observe the internal MutableLiveData
mPending.set(false);
super.observe(owner, new Observer<T>()
@Override
public void onChanged(@Nullable T t)
if (mPending.get())
observer.onChanged(t);
);
@MainThread
public void setValue(@Nullable T t)
mPending.set(true);
super.setValue(t);
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
public void call()
setValue(null);
public void callFromThread()
super.postValue(null);
【讨论】:
不起作用,因为处于后台的观察者在进入前台后不会获得更新的值。 @EgorNeliuba 你介意解释一下为什么这不起作用吗?我们要解决的问题不是阻止观察者返回前台后触发吗?【参考方案10】:更简单的解决方案是使用 EventLiveData 库:
implementation 'com.rugovit.eventlivedata:eventlivedata:1.0'
MutableEventLiveData<String> eventLiveData =new MutableEventLiveData<>();
viewModel.event.observe(this, Observer
// ...
)
您可以像使用常规实时数据一样使用它。它是 livedata 的扩展,支持 livedata 的所有功能。 与其他解决方案不同,它支持多个观察者。
Github 链接:https://github.com/rugovit/EventLiveData
【讨论】:
【参考方案11】:您可以使用this 文章中描述的 EventLiveData。它将解决您的问题,我在 2 个生产项目中使用了它。 它是 LiveData 扩展,就像 SingleLiveData 一样,但支持多个观察者。当观察者应该接收事件时,还允许自定义生命周期限制。例如,如果您不想在片段处于后台时接收事件。
EventLiveData 持有它永远观察的内部观察者,覆盖观察方法,将观察者保存到内部地图中,绕过原生 LiveData 事件调度机制。
你可以复制/粘贴整个类或导入库,这是更方便的方式
public class EventLiveData<T> extends LiveData<T>
private final HashMap<Observer<? super T>, EventObserverWrapper> observers= new HashMap<>();
private final Observer<T> internalObserver;
int mActiveCount = 0;
public EventLiveData()
this.internalObserver = (new Observer<T>()
@Override
public void onChanged(T t)
Iterator<Map.Entry<Observer<? super T>, EventObserverWrapper>> iterator = EventLiveData.this.observers.entrySet().iterator();
while (iterator.hasNext())
EventObserverWrapper wrapper= iterator.next().getValue();
if(wrapper.shouldBeActive())
wrapper.getObserver().onChanged(t);
);
private void internalObserve()
super.observeForever(this.internalObserver);
@MainThread
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer)
observe(owner, observer,STARTED,null);
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer, @NonNull Lifecycle.State minimumStateForSendingEvent)
observe(owner, observer,minimumStateForSendingEvent,null);
@MainThread
public void observeInOnStart(@NonNull LifecycleOwner owner, @NonNull Observer observer)
observe(owner, observer,STARTED, Lifecycle.Event.ON_STOP);
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer, @NonNull Lifecycle.State minimumStateForSendingEvent, Lifecycle.Event removeObserverEvent)
assertMainThread("observe");
assertNotNull(owner, "owner");
assertNotNull(observer, "observer");
assertNotNull(owner, "minimumStateForSendingEvent");
assertDestroyedState(minimumStateForSendingEvent);
assertMaximumEvent(removeObserverEvent);
if(minimumStateForSendingEvent==DESTROYED)
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement caller = stackTraceElements[3];
String className = caller.getClassName();
String methodName = caller.getMethodName();
IllegalArgumentException exception =
new IllegalArgumentException("State can not be equal to DESTROYED! : " +
"method " + className + "." + methodName +
", parameter " + minimumStateForSendingEvent);
throw sanitizeStackTrace(exception);
if (owner.getLifecycle().getCurrentState() == DESTROYED)
return;
EventLifecycleBoundEventObserver wrapper = new EventLifecycleBoundEventObserver(owner, observer);
wrapper.setMinimumStateForSendingEvent(minimumStateForSendingEvent);
wrapper.setMaximumEventForRemovingEvent(removeObserverEvent);
EventObserverWrapper existing = wrapper;
if(!observers.containsKey(observer))existing = observers.put(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner))
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
if (existing != null)
return;
owner.getLifecycle().addObserver(wrapper);
if (!super.hasObservers())
internalObserve();
@MainThread
@Override
public void observeForever(@NonNull Observer observer)
assertMainThread("observeForever");
assertNotNull(observer, "observer");
EventAlwaysActiveEventObserver wrapper = new EventAlwaysActiveEventObserver(observer);
EventObserverWrapper existing = wrapper;
if(!observers.containsKey(observer))existing = observers.put(observer, wrapper);
if (existing != null && existing instanceof EventLiveData.EventLifecycleBoundEventObserver)
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
if (existing != null)
return;
if (!super.hasObservers())
internalObserve();
wrapper.activeStateChanged(true);
/**
@inheritDoc
*/
@Override
public void removeObservers(@NonNull LifecycleOwner owner)
assertMainThread("removeObservers");
assertNotNull(owner, "owner");
Iterator<Map.Entry<Observer<? super T>, EventObserverWrapper>> iterator = EventLiveData.this.observers.entrySet().iterator();
while (iterator.hasNext())
Map.Entry<Observer<? super T>, EventObserverWrapper> entry=iterator.next();
if(entry.getValue() instanceof EventLiveData.EventLifecycleBoundEventObserver)
EventLifecycleBoundEventObserver eventLifecycleBoundObserver =(EventLifecycleBoundEventObserver) entry.getValue();
if(eventLifecycleBoundObserver.isAttachedTo(owner))this.observers.remove(entry.getKey());
@Override
public void removeObserver(@NonNull Observer observer)
assertMainThread("removeObserver");
assertNotNull(observer, "observer");
this.observers.remove(observer);
final protected void onActive()
protected void onActiveEvent()
protected void onInactive()
@SuppressWarnings("WeakerAccess")
public boolean hasObservers()
return observers.size() > 0;
@SuppressWarnings("WeakerAccess")
public boolean hasActiveObservers()
return mActiveCount > 0;
class EventLifecycleBoundEventObserver extends EventObserverWrapper implements LifecycleObserver
@NonNull
private final LifecycleOwner mOwner;
private Lifecycle.State MINIMUM_STATE_FOR_SENDING_EVENT= STARTED;
private Lifecycle.Event MAXIMUM_EVENT_FOR_REMOVING_EVENT= null;
EventLifecycleBoundEventObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer)
super(observer);
mOwner = owner;
public Lifecycle.State getMinimumStateForSendingEvent()
return MINIMUM_STATE_FOR_SENDING_EVENT;
public Lifecycle.Event getMaximumStateForRemovingEvent()
return MAXIMUM_EVENT_FOR_REMOVING_EVENT;
public void setMaximumEventForRemovingEvent(Lifecycle.Event MAXIMUM_EVENT_FOR_REMOVING_EVENT)
this.MAXIMUM_EVENT_FOR_REMOVING_EVENT = MAXIMUM_EVENT_FOR_REMOVING_EVENT;
public void setMinimumStateForSendingEvent(Lifecycle.State MINIMUM_STATE_FOR_SENDING_EVENT)
this.MINIMUM_STATE_FOR_SENDING_EVENT = MINIMUM_STATE_FOR_SENDING_EVENT;
@Override
boolean shouldBeActive()
Lifecycle.State state=mOwner.getLifecycle().getCurrentState();
return state.isAtLeast(MINIMUM_STATE_FOR_SENDING_EVENT);
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event)
if (mOwner.getLifecycle().getCurrentState() == DESTROYED||(MAXIMUM_EVENT_FOR_REMOVING_EVENT!=null&&MAXIMUM_EVENT_FOR_REMOVING_EVENT==event))
removeObserver(mObserver);
return;
activeStateChanged(shouldBeActive());
@Override
boolean isAttachedTo(LifecycleOwner owner)
return mOwner == owner;
@Override
void detachObserver()
mOwner.getLifecycle().removeObserver(this);
private abstract class EventObserverWrapper
protected final Observer<? super T> mObserver;
boolean mActive;
EventObserverWrapper(Observer<? super T> observer)
mObserver = observer;
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner)
return false;
void detachObserver()
public Observer<? super T> getObserver()
return mObserver;
void activeStateChanged(boolean newActive)
if (newActive == mActive)
return;
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = EventLiveData.this.mActiveCount == 0;
EventLiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive)
onActiveEvent();
if (EventLiveData.this.mActiveCount == 0 && !mActive)
onInactive();
private class EventAlwaysActiveEventObserver extends EventObserverWrapper
EventAlwaysActiveEventObserver(Observer<? super T> observer)
super(observer);
@Override
boolean shouldBeActive()
return true;
private void assertDestroyedState(@NonNull Lifecycle.State minimumStateForSendingEvent)
if(minimumStateForSendingEvent==DESTROYED)
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement caller = stackTraceElements[3];
String className = caller.getClassName();
String methodName = caller.getMethodName();
IllegalArgumentException exception =new IllegalArgumentException("State can not be equal to "+ minimumStateForSendingEvent +"method " + className + "." + methodName +", parameter minimumStateForSendingEvent");
throw sanitizeStackTrace(exception);
private void assertMaximumEvent(@NonNull Lifecycle.Event maximumEventForRemovingEvent)
if(maximumEventForRemovingEvent== Lifecycle.Event.ON_START||maximumEventForRemovingEvent== Lifecycle.Event.ON_CREATE
||maximumEventForRemovingEvent== Lifecycle.Event.ON_RESUME)
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement caller = stackTraceElements[3];
String className = caller.getClassName();
String methodName = caller.getMethodName();
IllegalArgumentException exception = new IllegalArgumentException("State can not be equal to "+maximumEventForRemovingEvent + "method " + className + "." + methodName +", parameter maximumEventForRemovingEvent" );
throw sanitizeStackTrace(exception);
private void assertMainThread(String methodName)
boolean isUiThread = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? Looper.getMainLooper().isCurrentThread() : Thread.currentThread() == Looper.getMainLooper().getThread();
if (!isUiThread) throw new IllegalStateException("Cannot invoke " + methodName + " on a background"+ " thread");
private void assertNotNull(Object value, String paramName)
if (value == null) throwParameterIsNullException(paramName);
private void throwParameterIsNullException(String paramName)
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement caller = stackTraceElements[3];
String className = caller.getClassName();
String methodName = caller.getMethodName();
IllegalArgumentException exception =
new IllegalArgumentException("Parameter specified as non-null is null: " +
"method " + className + "." + methodName +
", parameter " + paramName);
throw sanitizeStackTrace(exception);
private <T extends Throwable> T sanitizeStackTrace(T throwable) return sanitizeStackTrace(throwable, this.getClass().getName());
<T extends Throwable> T sanitizeStackTrace(T throwable, String classNameToDrop)
StackTraceElement[] stackTrace = throwable.getStackTrace();
int size = stackTrace.length;
int lastIntrinsic = -1;
for (int i = 0; i < size; i++)
if (classNameToDrop.equals(stackTrace[i].getClassName())) lastIntrinsic = i;
StackTraceElement[] newStackTrace = Arrays.copyOfRange(stackTrace, lastIntrinsic + 1, size);
throwable.setStackTrace(newStackTrace);
return throwable;
【讨论】:
【参考方案12】:在android.arch.lifecycle.LiveData#observe
函数调用之前忽略数据。
class IgnoreHistoryLiveData<T> : MutableLiveData<T>()
private val unactivedObservers = LinkedBlockingQueue<WrapperObserver<T>>()
override fun observe(owner: LifecycleOwner, observer: Observer<T>)
val wo = WrapperObserver<T>(observer)
unactivedObservers.add(wo)
super.observe(owner, wo)
override fun setValue(value: T)
while (unactivedObservers.isNotEmpty())
unactivedObservers.poll()?.actived = true
super.setValue(value)
private class WrapperObserver<T>(private val origin: Observer<T>) : Observer<T>
var actived = false
override fun onChanged(t: T?)
if (actived)
origin.onChanged(t)
【讨论】:
如果setValue
从未被调用,那么您将泄漏任何留在unactivedObservers
中的观察者
我认为WeakReference
可以解决内存泄漏问题
可能,但为什么不解决该模式的问题,这样您就不必使用WeakReference
。以上是关于LiveData 防止在开始观察时收到最后一个值的主要内容,如果未能解决你的问题,请参考以下文章