您可以使用本文中描述的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;
}
}