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.
Related
I have a Fragment that’s using View Binding, so it sets its _binding member variable in onCreateView and nulls it out in onDestroyView. In onViewCreated, I observe a LiveData from the view model using viewLifecycleOwner as the LifecycleOwner. (In reality this is split between a fragment and a base class, but I can’t see how that would explain any of this)
I can’t reproduce this in house, but crashlytics is reporting cases in the field where the LiveData’s observer is getting called back when the binding is null, making me think that somehow it’s being called after onDestroyView has been called. Any idea how that’s possible?
UPDATE: Turns out the observer was calling postDelayed on one of the views, so the Runnable was being executed (and accessing the binding) after onDestroyView had been called.
Thanks to #Zain and #EpicPandaForce for taking a look.
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.
I'm using an AndroidViewModel with a LiveData that is observed in a Fragment.
However, even though I'm using postValue from the LiveData, the observer registered in an activity triggers more than once. I know it's a common problem on LiveData but I haven't found yet a concrete solution.
Does somebody know why this happens?
Note: u need to provide the code.
Answer
multiple triggers Causes:
[Default] onChange() method in the observer will be called when the fragment is created (u will receive the last value emitted before the fragment get destroyed)
Or, you are using livedata.observe(this,...), (if it's true you need to use livedata.observe(viewlifecycleowner,...)
Resource:
https://proandroiddev.com/5-common-mistakes-when-using-architecture-components-403e9899f4cb
https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150
https://medium.com/androiddevelopers/viewmodels-and-livedata-patterns-antipatterns-21efaef74a54
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.
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.