Using stateflow for mutableList in Android - android

Working on a project where we need to have a list of items in a view model. The type is a custom data class.
Until now, I have used a MutableLiveData to store the state of the list. The list will be updated when a user scans an item on an RFID reader that we have connected to the device. When scanned, an item will be fetched from a server and the list will be updated accordingly.
I want to try and move on to using a StateFlow instead, but I'm running into an issue here.
When a new item is scanned, I'm updating the mutable list with the add command and later on updating the corresponding item in the list. This does not trigger the LiveData or StateFlow observers/collectors - but with LiveData I could assign the list to itself after I'm done with updating it. (_listOfItems.value = _listOfItems.value) as this would notify observers.
This does not work with StateFlow however, since it only trigger when the reference changes (which it doesn't since it's the same list, just with new/changed items in it).
I'm aware that there are probably some issues with using a mutable list and coroutines to update the same list, since it might collide if trying to update the list at the same time, or something like that.
So, generally the question is: what's the best approach when having a list in a view model and having the UI update whenever the content of the list changes?

It would be impossible to use a MutableList in a StateFlow and make it update because StateFlow always does an equals comparison with the previous value, and since the previous value is an instance of the same list, they will always be considered equal.
You could make this work with SharedFlow, which does not compare values with the previous.
It is however very error prone to use mutable classes with a SharedFlow/StateFlow (or even LiveData) in general because the data could be getting read from and written to from multiple different places. Very hard to manage.
One solution is to create a copy of the list every time you send it to the flow:
myMutableStateFlow.value = myMutableList.toList()
If you want code that's even easier to manage, possibly at the expense of performance, don't use mutable Lists at all. Use read-only Lists. You could put it in a var property, or just modify the value of your StateFlow directly.
myMutableStateFlow.value += someNewItems
// where myMutableStateFlow's type is a List, not MutableList

Related

LiveData, is it possible to observe specific value

I am using live data to sync qty change between duplicate items on the same view. So if there are 7 items observing qty updates, and 3 of them have the same ids, if one of them is triggered all of the 7 will follow even though 3 of them should be refreshed.
My question is, would it be possible to subscribe to a specific value, instead of the whole field kind of like a topic subscription just so that those 3 items with the same id would only be triggered
When you observe a LiveData, your listener will get all updates to the object stored in the LiveData with every update. It's not possible to tell a LiveData to be "smart" about which specific nested values you want.
If you want to transform the object inside the LiveData into a different object that meets your needs, you can use Transformations.map() to create a new LiveData based on the contents of the one you have now. It will be up to you to make sure the code only generates new LiveData objects if something of interest changes in the original.

MutableLiveData<ArrayList<T>> vs MutableLiveData<List<T>>. Why should we use List here?

I created a library here: https://github.com/chanjungkim/ALiveData
This library is made because of MutableLiveData<ArrayList<T>>. Many people who learns about LiveData complains or they are confused with this type when they need to manipulate(add, remove, etc) the MutableLiveData. That's because ArrayList is easy to manipulate and _arrayList.value!!.add(item) or _arrayList.value!!.remove(0) seems to notify. But they don't.
At the end, when we want to notify, we must assign a value like _arrayList.value!! = mList. ArrayList and List both need to set the data like _arrayList.value!! = mArrayList or _arrayList.value!! = mList.
My question is List doesn't have add(), remove(), etc. On the other hand, ArrayList already has those functions and helps us manipulate the list much easier.
some people suggested like this
_list.value = list.value.toMutableList().doWhatever().toList()
So, what's the point of using List over ArrayList? Could you give me example with the explanation of using it?
LiveData can be used in different ways, and of course there is no one correct way, but a very common way of using it is within the Android MVVM architecture recommended by Google for use in Android apps.
In this architecture, the Activity (or Fragment) observe the LiveData of the ViewModel. When doing this, the goal would be to make the UI as 'dumb' as possible, where you try to handle as much of the app logic and behaviour in the ViewModel, and the Activity simply observes and reflects it on the UI.
In a case like this, it is often preferable for the values of the LiveData being observed to be immutable.
By doing this, it limits the Activity from being able to manipulate the data it is observing, such as add()ing or remove()ing anything from it. As just described, the goal should be to limit the UI's ability to make exactly these type of changes. If the Activity wants to add() an item to an ArrayList that it is observing, it should instead do this by calling a method on the ViewModel, which will in turn update it's own LiveData.value to the new, updated list, which will in turn be observed by the Activity and updated on the UI.
By only allowing the Activity to observe the immutable values, it helps enforce this separation of concerns, and limits any accidental 'leak' of logic into the Activity itself.
This idea can be extended further by ensuring that the observed values are of type LiveData, and not MutableLiveData. Using the latter can allow the Activity to manipulate the live data on its own, and break the MVVM pattern.
A List is an interface, and defines the methods that must be implemented by any classes that would like to behave like a list. It can be considered the 'most basic' version of a list, and only defines the minimum requirements for an implementing class to behave like a list.
In the same way, the List interface itself extends the Collections interface, which in turn extends the Iterable interface. Each one adds more functionality to the one before it... kind of like lego blocks stacked on top of each other, creating more complex shapes.
An ArrayList is a class, which implements MutableList (which itself implements List). This means that an ArrayList can be instantiated, and passed around as an actual object. Because of this object oriented design, and according to the Liskov substitution principle, any class (or interface) can be replaced by a subclass (or class implementing the interface) interchangeably.
This is a fundamental principle to object oriented design. It helps break parts of the application down into smaller, more basic and more manageable pieces, and then grow as required.
To answer your question more specifically, if the class that is observing the LiveData only cares about the methods defined in the List interface, then that is the all it requires to know about the value. The actual value could in fact be an ArrayList, a MutableList or even a custom class MyOwnFancyList<E>: List<E>, it does not matter to the observer, just as long as it implements the List interface.

Is it possible to get only changed data with query observe in ObjectBox?

I was reading the doc about observing queries.
Query<Task> query = taskBox.query().equal(Task_.completed, false).build();
subscription = query.subscribe().observer(data -> updateUi(data));
From what i understand , this code returns all the data every time. but for RecyclerView add/remove animation to work, we need to know which data is changed and we need to know what kind of change is happened to data (remove/change/add).
is there anyway to get changed data only?
It's not a responsibility of ObjectBox to define a change. There is DiffUtil that responsible for that in android. If you google that you can find tons of examples (e.g. sample). The only advice there is to put DiffUtil payload to background thread if your list contains lots of items or items are fat(contain dozens of fields).

DiffUtil for multiple instances of the same list

I have a RecyclerView with elements updated via WebSocket. The update can affect several elements of the list in different places. I'd like to used DiffUtil to update elements of the RecycleView. The socket update itself doesn't contain the whole list element structure but just a few fields. So in order to update I need get the current data list from the adapter, look up for a elements that needs to be updated, update the fields and pass the new list into DiffUtils to compare with the current one. The problem is that when I update object it also automatically updates in a RecyclerView adapter because it's kept as a reference. So when I get the update from WebSocket I already don't have an "old" list to be compared with updated one.
Finally, I have found solution on Medium. Here it is https://android.jlelse.eu/rxjava-and-immutable-diffcallback-in-android-f4637078b03b

How to properly use LiveData with RecycleView

I have a project that loads a list from the server. This data will eventually be stored into a database, but for now is stored in memory in a MutableLiveData. A RecyclerView's adapter is watching the data and displaying it. So far everything is working as expected, using a FAB the user can post a new entry which will go at the top of the list, on success I get a 200 and here's the main part where I'm getting lost...
When I want to add a single item to a list stored in a LiveData, the observer is unaware of the delta. I currently make a call to RecyclerView.Adapter.notifyDataSetChanged(), though the ideal in my case would be to call notifyItemInserted(0) or in other cases I can see various other notifications. What the best way to do this? The lifecycle architecture library appears to be very well thought of, I assume I'm missing something simple. I can't imagine having to manually perform a diff between the lists?

Categories

Resources