How to clear LiveData stored value?

后端 未结 7 1174
暖寄归人
暖寄归人 2021-01-30 02:34

According to LiveData documentation:

The LiveData class provides the following advantages:

...

Always up to date data: If a Li

相关标签:
7条回答
  • 2021-01-30 02:45

    If you need simple solution, try this one:

    class SingleLiveData<T> : MutableLiveData<T?>() {
    
        override fun observe(owner: LifecycleOwner, observer: Observer<in T?>) {
            super.observe(owner, Observer { t ->
                if (t != null) {
                    observer.onChanged(t)
                    postValue(null)
                }
            })
        }
    }
    

    Use it like a regular MutableLiveData

    0 讨论(0)
  • 2021-01-30 02:51

    Might be an ugly hack but... Note: it requires RxJava

    menuRepository
                .getMenuTypeAndMenuEntity(menuId)
                .flatMap { Single.fromCallable { menuTypeAndId.postValue(Pair(it.first, menuId)) } }
                .flatMap { Single.timer(200, TimeUnit.MILLISECONDS) }
                .subscribe(
                    { menuTypeAndId.postValue(null) },
                    { Log.d(MenuViewModel.TAG, "onError: ${it.printStackTrace()}") }
                )
    
    0 讨论(0)
  • 2021-01-30 02:57

    Update

    There are actually a few ways to resolve this issue. They are summarized nicely in the article LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case). This is written by a fellow Googler who works with the Architecture Components team.

    TL;DR A more robust approach is to use an Event wrapper class, which you can see an example of at the bottom of the article.

    This pattern has made it's way into numerous Android samples, for example:

    • Plaid
    • Architecture Blueprints
    • IOSched

    Why is an Event wrapper preferred over SingleLiveEvent?

    One issue with SingleLiveEvent is that if there are multiple observers to a SingleLiveEvent, only one of them will be notified when that data has changed - this can introduce subtle bugs and is hard to work around.

    Using an Event wrapper class, all of your observers will be notified as normal. You can then choose to either explicitly "handle" the content (content is only "handled" once) or peek at the content, which always returns whatever the latest "content" was. In the dialog example, this means you can always see what the last message was with peek, but ensure that for every new message, the dialog only is triggered once, using getContentIfNotHandled.

    Old Response

    Alex's response in the comments is I think exactly what you're looking for. There's sample code for a class called SingleLiveEvent. The purpose of this class is described as:

    A lifecycle-aware observable that sends only new updates after subscription, used for events like navigation and Snackbar messages.

    This avoids a common problem with events: on configuration change (like rotation) 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 call().

    0 讨论(0)
  • 2021-01-30 02:57

    In my case SingleLiveEvent doesn't help. I use this code:

    private MutableLiveData<Boolean> someLiveData;
    private final Observer<Boolean> someObserver = new Observer<Boolean>() {
        @Override
        public void onChanged(@Nullable Boolean aBoolean) {
            if (aBoolean != null) {
                // doing work
                ...
    
                // reset LiveData value  
                someLiveData.postValue(null);
            }
        }
    };
    
    0 讨论(0)
  • 2021-01-30 02:58

    You need to use SingleLiveEvent for this case

    class SingleLiveEvent<T> : MutableLiveData<T>() {
    
        private val pending = AtomicBoolean(false)
    
        @MainThread
        override fun observe(owner: LifecycleOwner, observer: Observer<T>) {
    
            if (hasActiveObservers()) {
                Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
            }
    
            // Observe the internal MutableLiveData
            super.observe(owner, Observer<T> { t ->
                if (pending.compareAndSet(true, false)) {
                    observer.onChanged(t)
                }
            })
        }
    
        @MainThread
        override fun setValue(t: T?) {
            pending.set(true)
            super.setValue(t)
        }
    
        /**
         * Used for cases where T is Void, to make calls cleaner.
         */
        @MainThread
        fun call() {
            value = null
        }
    
        companion object {
            private const val TAG = "SingleLiveEvent"
        }
    }
    

    And inside you viewmodel class create object like:

     val snackbarMessage = SingleLiveEvent<Int>()
    
    0 讨论(0)
  • 2021-01-30 03:02

    The best solution I found is live event library which works perfectly if you have multiple observers:

    class LiveEventViewModel : ViewModel() {
        private val clickedState = LiveEvent<String>()
        val state: LiveData<String> = clickedState
    
        fun clicked() {
            clickedState.value = ...
        }
    }
    
    0 讨论(0)
提交回复
热议问题