A livedata in a viewmodel can just observed by one place? - android

I have a livedata in a viewmodel.
and i observe the livedata in a fragment, another class,
when i change the livedata value, only the fragment can receive the notification of livedata change. not another class.
i wonder just only one place(ex: fragment, activity etc) can observe a livedata of viewmodel?

You are not getting it right. The way MVVM works is view interact with viewModel which is observer class and viewModel then interacts with repo class for db/remote operations. Reason why you are observing live data in fragment/activity is because as per design patter view can only access ViewModel that's why you are only able to observe it from fragment/activity class

The livedata can be observed by as many observers as you want.The observer if implements LifecycleOwner interface will get notified when in running state or you can observe it forever irrespective of lifecycle of the observer by using observeForever. But you will have to manually remove the observer to stop observing it.
LiveData considers an observer, which is represented by the Observer class, to be in an active state if its lifecycle is in the STARTED or RESUMED state. LiveData only notifies active observers about updates. Inactive observers registered to watch LiveData objects aren't notified about changes.

Related

Clarification about LiveData's strong references in ViewModels

The ViewModel documentation quotes:
Caution: A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.
And the LiveData documentation states next:
LiveData keeps a strong reference to the observer and the owner as long as the given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to the observer & the owner.
So, if we have a LiveData variable defined in a ViewModel, and we set to observe it using a fragment (or activity) as owner and/or observer, does this mean that we are breaking the rule stated in the ViewModel documentation? Does the action of setting such type of owner/observer, indirectly place an Activity context reference within the ViewModel?
By the LiveData documentation seems it shouldn't be a concern as it will take care of removing the references when required, but I would like to know if I am missing something, as seems the documentation is contradicting itself.
I'm planning to write a post to explain about the issue you asked. But I have not published it. You can read my draft blog in this link: Exploring LiveData in Android
Or short answer for you:
LifecycleOwner: is an interface that has only one method: getLifecyle(). This method returns a Lifecycle object.
Lifecycle: is a class that has states and allows other objects to observe its state changes.
Activity and Fragment: implement LifecycleOwner interface. In the getLifecycle() method, we return a LifecycleRegistry object as Lifecycle. The LifecycleRegister class extends Lifecycle class. This class helps Activity and Fragment notify observers about their state change.
ObserverWrapper is an inner class in LiveData. This class will help LiveData know the state of LifecycleOwner and the latest version of data that the Observer is having.
LifecycleBoundObserver is also an inner class in LiveData. This class extends OberverWrapper to provide LiveData the state of LifecycleOwner and keeps Observer and the data’s version that the Observer is having. It also implements LifecycleEventObserver to observe the Lifecyle’state changes ( in our case, it is Activity’s state and Fragment’s state). This class helps LiveData know the state of Activity (Fragment) and the data version that the Observer is having, so LiveData can decide whether it will notify Activity (Fragment) about an update or not.

How to make the viewmodel observe the repository without lifecycle object

I'm building an android application with MVVM design and I have multiple layers(view, ViewModel, repository and dataSource both local and remote).
I want that my repository object will observe the dataSources, do all of his logic for how and when storing cache, map the data to the correct form for the above layer and only then notify the view model about the new data.
Similar to that I want the ViewModel to observe the repository for new data arrival, then doing all the business logic and only after that notify the view.
My problem is that LiveData require lifecycle object that the ViewModel and
the repository doesn't have.
I read about using simple observable rather than LiveData but I also read that it is bad practice because the observables are alive forever and this could lead to wierd crashes. In addition, I have PageKeyedDataSource which only returns LiveData.
I also read about using Transformations.map but what if I don't want only to map the data but rather to do something more complex.
Is There a way to make one layer safely observe another layer without creating a chain of LiveData observables from the view layer to the DataSource?
note: my ViewModel is used in multiple fragments if that somehow relevant.
My problem is that LiveData require lifecycle object
Actually, lifecycle is optional. There is an observeForever(Observer) method in LiveData that does not require lifecycle. But that means you should also manually call removeObserver(Observer) when your repository finished work, otherwise it will be a leak.
This really is not much different to using Rx's observables. In both cases you should override onCleared() in your viewmodel and manually unsubscribe (or remove observer) from the repository.
observables are alive forever and this could lead to wierd crashes
Nope, they are alive until you dispose them, but you must do it manually as Rx does not provide lifecycle-aware subscription.
Is There a way to make one layer safely observe another layer without creating a chain of LiveData observables from the view layer to the DataSource?
As your wrote, you are trying to do a View-that-observes-ViewModel-that-observes-Repo-that-observes-DataSource. It is already a chain, you should deal with it.
It is possible to to safely observe LiveData from ViewModel, cause View has a lifecycle and LiveData has lifecycle-aware observe.
But Repo and DataSource do not have lifecycles thus you should manually manage subscriptions. It is possible both with LiveData and Rx observables - you can choose whichever you prefer.
1.First of all, if you need context in viewmodel use AndroidViewModel .
2.Don't do any business logic in Viewmodel class as it's just mediator rather do calculations in repository class
3.use rxjava/rxkotlin in repository and return observable object to Viewmodel from repository method, once Viewmodel gets notified update view.
You could use DataBinding to reflect the ViewModel data in you UI. https://developer.android.com/topic/libraries/data-binding
An added benefit is that you write less boilerplate code.

Will it cause resource leakage if I have a long life LifeCycleOwner keep observing LiveData?

In certain case like Home Widget (AppWidgetProvider), I don't have access to Activity or Fragment.
Usually, I use ProcessLifecycleOwner.get(), or the following LifeCycleOwner to observe LiveData.
public enum ForeverStartLifecycleOwner implements LifecycleOwner {
INSTANCE;
private final LifecycleRegistry mLifecycleRegistry;
ForeverStartLifecycleOwner() {
mLifecycleRegistry = new LifecycleRegistry(this);
mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
}
#NonNull
#Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
}
In most situation, in the callback of LiveData, I will try to remove LifeCycleOwner from further observing LiveData, by using liveData.removeObserver.
However, there are situation where
LiveData fails to trigger callback.
Hence, I didn't remove LifeCycleOwner from LiveData in LiveData's callback.
In such situation, will it cause resource leakage? For instance, GC notice a long life LifeCycleOwner is observing LiveData A. Although LiveData A is already out of scope, GC will not free-up LiveData A, because a long living LifeCycleObserver still observing it?
If so, how can I resolve this kind of leakage?
will it cause resource leakage?
Answer : I don't think so that this kind of scenario will make memory leak.
Why?
Because, as we can see that once LiveData is out of scope for any LifecyclerOwner, it removes reference if you set your LifecycleOwner at DESTROYED state.
see observe() method documentation;
obesrve() :
Adds the given observer to the observers list within the lifespan of
the given owner. The events are dispatched on the main thread. If
LiveData already has data set, it will be delivered to the observer.
The observer will only receive events if the owner is in STARTED or
RESUMED state (active).
If the owner moves to the DESTROYED state, the observer will
automatically be removed.
When data changes while the owner is not active, it will not receive
any updates. If it becomes active again, it will receive the last
available data automatically.
LiveData keeps a strong reference to the observer and the owner as
long as the given LifecycleOwner is not destroyed. When it is
destroyed, LiveData removes references to the observer & the owner.
If the given owner is already in DESTROYED state, LiveData ignores the
call.
If the given owner, observer tuple is already in the list, the call is
ignored. If the observer is already in the list with another owner,
LiveData throws an IllegalArgumentException.
TL;DR
So, according to above documentation, from line :
If the owner moves to the DESTROYED state, the observer will automatically be removed.
If the given owner is already in DESTROYED state, LiveData ignores
the call.
it's clear that if your LifecycleOwner has no scope (already in DESTROYED state), then LiveData removes it's strong reference thus there's no chance of memory leak.
how can I resolve this kind of leakage? & get callback all the time:
Answer : You've already created your own LifecycleOwner, so I'll suggest you to handle it yourself. make your LiveData to observeForever() & handle removal (removeObserver()) yourself once your LifecycleOwner reaches to DESTROYED state.
this will not cause memory leak. because it's stated in document:
(This means that the given observer will receive all events and will never be automatically removed)
observeForever() :
Adds the given observer to the observers list. This call is similar to
observe(LifecycleOwner, Observer) with a LifecycleOwner, which is
always active. This means that the given observer will receive all
events and will never be automatically removed. You should manually
call removeObserver(Observer) to stop observing this LiveData. While
LiveData has one of such observers, it will be considered as active.
If the observer was already added with an owner to this LiveData,
LiveData throws an IllegalArgumentException.
This will help you receive callback all the time, you just need to handle how you can remove callback once done.
Hope it helps !
In above example, if don’t clear that reference explicitly (as we would usually do in activity/fragments onStop()); there will be a risk of memory leak.

Android MVVM: How to subscribe to a network call by LiveData in ViewModel

In MVVM ViewModel generally subscribes to network call and then inform the UI i.e. (Activity or Fragment) for updating the UI like loading, success or failure. In the case of LiveData inside ViewModel, how would you observe network call changes. For observing LiveData inside ViewModel ideally it should be lifecycle aware, how to achieve this. I am using data binding to update UI so I want to listen to results in ViewModel.
You need to use Transformations.map or Transformations.switchMap functions in your ViewModel https://developer.android.com/reference/android/arch/lifecycle/Transformations

What is the difference between Observer and LifecycleObserver?

I am struggling to understand the difference between LiveData being a LifecycleObserver and the Observer that the LiveData object receives in the observe() method.
Am I right saying that the LiveData is a LifecycleObserver and so it knows about the Activity because of it?
And that the Observer received in the observe() method has nothing to do with LifecycleObserver because it is there just to execute the onChange() method when there is a change in LiveData?
Am I right saying that the LiveData is a LifecycleObserver and so it knows about the Activity because of it?
Yes.
And that the Observer received in the observe() method has nothing to do with LifecycleObserver because it is there just to execute the onChange() method when there is a change in LiveData?
Yes.
As the name suggests, a LifecycleObserver is supposed to keep track of changes happening to the lifecycle of its parent (Activity or Fragment or any other LifecycleOwner), making LiveData lifecycle-aware.
The Observer on the other hand keeps track of changes happening to the value of this LiveData object.
So you are correct. Observer has nothing to do with LifecycleObserver.

Categories

Resources