【问题标题】:LiveData prevent receive the last value when start observingLiveData 防止在开始观察时收到最后一个值
【发布时间】: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库。

标签: android android-livedata android-architecture-components android-viewmodel mutablelivedata


【解决方案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.lifecycleandroidx.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,使其仅在添加观察者时通知视图。

        另一种选择是简单地忽略回调

        1. 向 ViewModel 添加一个标志。

          private boolean isFirstTime = true;
          
          public boolean isFirstTime() { return isFirstTime; }
          
          public boolean onObserverAdded() { isFirstTime = false; }`
          
        2. 在回调中添加检查

          @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
          }
          
        3. 添加观察者后最后调用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,它仅在调用setValuepostValue 后才向观察者发出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&lt;Event&lt;T&gt;&gt;,但实际上这只是 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
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-09-13
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-06-23
                  • 1970-01-01
                  • 2022-01-16
                  相关资源
                  最近更新 更多