Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to observe the livedata with multiple observe for correct way in Android?

I have an Activity, and it will turn to the fragment-A and then turn to the fragment-B like the following.

Activity -> Fragment-A -> Fragment-B

situation 1

These two fragment observe the same LiveData for showing snackBar like the following .

viewModel.responseData.observe(this, Observer {
            it.getContentIfNotHandled()?.let {
            showSnackBar(it)
}

The livedata in viewModel:

var responseData = MutableLiveData<Event<String>>()
responseData.value = Event("$message")

Error: When I use the above code. It only show the snackBar at fragment-A. The fragment-B can not get the value.

situation 2

When I change the code to the following

viewModel.responseData.observe(this, Observer {
            showSnackBar(it.peekContent())
})

The both fragment can get the value.

Error:

After close the fragment and turn again. It show the snackBar because the value of responseData still exist. But I did not send the message.

Event class reference from Google is like the following:

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package bbin.mobile.ballbet.support

import androidx.lifecycle.Observer
import timber.log.Timber

/**
 * Used as a wrapper for data that is exposed via a LiveData that represents an event.
 */
open class Event<out T>(private val content: T) {

    var hasBeenHandled = false
        private set // Allow external read but not write

    /**
     * Returns the content and prevents its use again.
     */
    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }

    /**
     * Returns the content, even if it's already been handled.
     */
    fun peekContent(): T = content
}

/**
 * An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has
 * already been handled.
 *
 * [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled.
 */
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let {
            onEventUnhandledContent(it)
        }
    }
}

I want the fragment show the correct snackBar message for them.

How to observe the livedata for multiple fragment for correct way in Android?

Thanks in advance.

like image 702
Wun Avatar asked Sep 24 '19 07:09

Wun


People also ask

Can LiveData have multiple observers?

In theory, we can observe livedata with multiple observers, just like the good old pub-sub pattern, right? Well, let's test this out. Let's create a super simple livedata. Then observe it 10 times, and print some log when the data changes.

In which method should you observe a LiveData object?

Observe LiveData objects In most cases, an app component's onCreate() method is the right place to begin observing a LiveData object for the following reasons: To ensure the system doesn't make redundant calls from an activity or fragment's onResume() method.

Why LiveData Observer is being triggered twice?

Your fragment A views are created again and the observer is getting triggered once with cached livedata value and antoher time because the vendor type was set again in onViewCreated. Since we are using switchmap in viewmodel and the livedata was set again the observer in fragment A was getting triggered twice.

Can we use same ViewModel for two activities?

In android, we can use ViewModel to share data between various fragments or activities by sharing the same ViewModel among all the fragments and they can access everything defined in the ViewModel. This is one way to have communication between fragments or activities.


1 Answers

You are observing the LiveData correctly, it is how the Event class is designed.

When you do

viewModel.responseData.observe(this, Observer {
            it.getContentIfNotHandled()?.let {
            showSnackBar(it)
}

getContentIfNotHandled will return content only once until there is a new value set again. If FragmentA consumes this first FragmentB will not be able to consume the same value. This is the reason peekContent works since it will always return the current value even though the event has been consumed.

If there is a solid reason where you need to show this Snackbar msg in both fragments I suggest you observe on different LiveData instances for each fragment.

You could do this by returning a new LiveData<Event<String>> everytime viewModel.getResponseData() is invoked.

like image 129
Arka Prava Basu Avatar answered Sep 28 '22 00:09

Arka Prava Basu