Changes to LiveData of composite objects - android

I want to make sure I understand correctly when is the onChanged method of a LiveData's Observer called.
Let's say we have an object A which has some primitives types
(some ints, some strings, etc.) and an object B as fields.
I know that onChanged is called when I call setValue. I'm pretty sure that it is also called when A's primitive fields change, or when I reassign the object field to a new instance, and that it is NOT called when I change any of B's fields.
Please correct me if I'm wrong.
Do these rules also apply to a LiveData object fetched from Room?
Are there any other cases where onChanged is called?

The fact is that the onChanged method of the LiveData's Observer is only called when the containing value of the LiveData is being set using setValue() or postValue() method. There is no mechanism to observe fields inside an object that is held by a LiveData. As a result, by changing the value of fields inside object-A, the observer shouldn't be notified.
On the other hand, as you know, the methods that are provided by Room to query on a db are able to return LiveData<SomeType> instead of SomeType. Under the hood, Room creates and registers a ContentObserver on your query's table(s) to get aware of changes in it. So, every time a change occurs on the data, Room gets notified using the mentioned ContentObserver, then fetches the query result again and post it on the LiveData.

Related

Get data from ViewModel after setting up the observer

I have a fragment, which contains LiveData, and SwiperRefreshLauout. In onCreateView I have set the observer for some String.
User, while playing with fragment, can change the value of this string, but it should be only temporary. Whenever user will trigger onRefreshListener, the String should get "default" data, that came from observer.
I'd like to know, if there's any way to call data from observer again, in onRefreshListener, or I have to remove observer from onCreateView, and make another one after onRefreshListener is called?
Dummy scenario:
We have String, called test. In OnCreateView, we are setting the observer to the ViewModel, and get some data from database to the test string. Let's say it'll be name - "Mark". When user will pick from spinner another name: "Carl" the test string will have value of "Carl" now. User would like to refresh the UI of layout, and now, the test string should have value - "Mark" again.
If I understand your situation correctly, here I have a suggestion:
In the onCreateView setup an observer of your live data, viewModel.data.observe(...)
At the same time you could call the function responsible for fetching the data, viewModel.fetchData("initialValue"). On the other hand, since this is the initial call, you could use the init section of the View Model class and call there the initial fetch. init { fetchData("initialValue") }
Then, everytime the pull to refresh callback is executed, inside the onRefresh you could call the function to fetch the data, but this time with the temp value viewModel.fetchData("defaultValue")
So, everytime you call the viewModel.fetchData("anyValue") the data LiveData will be refreshed and since you are already subscribed in the onCreateView then you will receive the updates there.
if this is not clear, please share some code in this way, I can give better advise.

Android View Model

If I call lets say some function A in init block of View Model which will update live data and after that I m observing this live data in onViewCreated of activity. Then it is correct or not.? It will get that value which is stored in live data? Or I have to call function A after observing live data in activity.
And if it is working why it will work?
LiveData is just a data holder. It will store the latest value of the state. If you call function A in the init block, the live data will probably get its value before you start observing it in your Fragment/Activity i.e. when you observe it, you will get the new value of live data updated by function A.
If you call function A after setting up the observer, you will probably see the initial value of the LiveData first and then the new value will be observed.
In either case, it doesn't make much of a difference, because the value set by function A will anyway be processed. But is you want to set the value of LiveData as soon as the Activity/Fragment loads, init block of the ViewModel is a good choice.
Also note that if you call function A from the Fragment/Activity, it will be called every time the view gets destroyed and recreated. So if you are doing some operation in function A which should not be repeated on every view recreation, ViewModel's init block is the only option here.

How to initialize the LiveData in ViewModel for the first time in android? and which factory to use?

I want to initialize the LiveData value when the app is launched, not every time the orientation changes.
Can I use the constructor of the subclass of ViewModel for it?
Instead of LiveData which pushes the last value to observers for every config change (like a RxJava BehaviourSubject), you should use something which pushes the event once.
You can use:
SingleLiveEvent: Send the event to only 1 observer, check here and here or alternatives here
LiveEvent: Send the event to all the observers, check here
Both of those approaches will not cache events, which means that an observer should be already observing the *LiveEvent to receive it
You can find articles online about alternative approaches but the philosophy behind them is probably the same

Observing Room table with without LifecycleOwner reference

I have a component in my app that performs specific work when the database gets updated. In order to observe Room table, I need to use LiveData which requires me to pass LifecycleOwner. My component has nothing to do with any of the views so I don't have a Lifecycle. How can I observe on Room table without a reference to LifecycleOwner? I am using Kotlin and Coroutines.
You may use LiveData.observeForever(Observer). Do not forget to call LiveData.removeObserver(Observer) once you do not want to get updates anymore, as using this method you register an observer that will receive updates forever (as the method's name suggests). (Docs source)

Do I need to dispose() Publishers created using LiveDataReactiveStreams

Let's say I have an Flowable that is shared among different parts of the application.
In each fragment where I want to observe it, I convert it to a LiveData with LiveDataReactiveStreams.fromPublisher to avoid leaks and crashes. I now have a LiveData that wraps my Flowable.
I then pass the LiveData to my ViewModel (in the ViewModelFactory). As far as I understand, I can go ahead and use the LiveData without worrying about leaks.
Now, instead of observing the LiveData directly, I am tempted to convert it back to a Flowable with LiveDataReactiveStreams.toPublisher and Flowable.fromPublisher and subscribe to the Flowable instead. This is now a Flowable that wraps a LiveData which wraps a Flowable
My question is: Do I have to worry about disposing the subscriptions to this Flowable? My hope is that the LiveData will act as a "barrier", preventing my context to leak back up to the root Flowable, but I am not so sure about that.
In other words:
Flowable A exists in a global context
In each fragment, A is wrapped in LiveData B which is set as a property of the fragments ViewModel
When normally I would observe LiveData B, I instead wrap it in Flowable C
I subscribe to Flowable C and ignore the returned disposable
Will views accessed in C leak up to A when the fragment is destroyed?
Considering the current implementation, you still need to care for the subscriptions manually. The lifecycle is only used for handling the observation of the live data.
mLiveData.observe(mLifecycle, LiveDataSubscription.this);
The observation is only canceled automatically when a non-positive amount of items was requested and an error is sent. This then disposes the subscription. Since the producer never completes it'll never dispose the subscription by itself and thus you'll leak the subscription if you don't dispose it yourself.

Categories

Resources