Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Notify Observer when item is added to List of LiveData

I need to get an Observer event when the item is added to the List of LiveData. But as far as I understand the event receives only when I replace the old list with a new one. For example when I do the next:

list.value = mutableListOf(IssuePost(UserEntity(name, email, photoUrl), issueEntity)) 

Observer gets event. But when I just add item to value, Observer is silent. Could you please give me advice on how I can implement what I need?

like image 356
Ruslan Leshchenko Avatar asked Dec 22 '17 12:12

Ruslan Leshchenko


People also ask

How do you observe LiveData in activity?

You usually create an Observer object in a UI controller, such as an activity or fragment. Attach the Observer object to the LiveData object using the observe() method. The observe() method takes a LifecycleOwner object. This subscribes the Observer object to the LiveData object so that it is notified of changes.

In which method should you observe a LiveData object?

Initialize, Update, Observe LiveData LiveData is a wrapper on an object which can be observed from any UI component via a getter method.

Is LiveData deprecated?

This function is deprecated. This extension method is not required when using Kotlin 1.4.

Why use flow instead of LiveData?

StateFlow and LiveData have similarities. Both are observable data holder classes, and both follow a similar pattern when used in your app architecture. The StateFlow and LiveData do behave differently: StateFlow requires an initial state to be passed into the constructor, while LiveData does not.


2 Answers

Internally, LiveData keeps track of each change as a version number (simple counter stored as an int). Calling setValue() increments this version and updates any observers with the new data (only if the observer's version number is less than the LiveData's version).

It appears the only way to start this process is by calling setValue() or postValue(). The side-effect is if the LiveData's underlying data structure has changed (such as adding an element to a Collection), nothing will happen to communicate this to the observers.

Thus, you will have to call setValue() after adding an item to your list. I have provided two ways you could approach this below.

Option 1

Keep the list outside of the LiveData and update with the reference any time the list contents change.

private val mIssuePosts = ArrayList<IssuePost>() private val mIssuePostLiveData = MutableLiveData<List<IssuePost>>()  fun addIssuePost(issuePost: IssuePost) {    mIssuePosts.add(issuePost)    mIssuePostLiveData.value = mIssuePosts } 

Option 2

Keep track of the list via the LiveData and update the LiveData with its own value whenever the list contents change.

private val mIssuePostLiveData = MutableLiveData<MutableList<IssuePost>>()  init {    mIssuePostLiveData.value = ArrayList() }  fun addIssuePost(issuePost: IssuePost) {     mIssuePostLiveData.value?.add(issuePost)     mIssuePostLiveData.value = mIssuePostLiveData.value } 

Either of these solutions should help you from having to create a new list every time you modify the current list just to notify the observers.

UPDATE:

I've been using similar techniques for a while now as Gnzlt has mentioned in his answer to use a Kotlin extension function to assign the LiveData to itself to simplify the code. This is essentially Option 2 automated :) I would recommend doing that.

like image 186
Programmer001 Avatar answered Sep 17 '22 08:09

Programmer001


I use a Kotlin Extension Function to make it easier:

fun <T> MutableLiveData<T>.notifyObserver() {     this.value = this.value } 

Then use it in any MutableLiveData like this:

fun addIssuePost(issuePost: IssuePost) {     mIssuePostLiveData.value?.add(issuePost)     mIssuePostLiveData.notifyObserver() } 
like image 35
Gnzlt Avatar answered Sep 17 '22 08:09

Gnzlt