LiveData observing in Fragment - android

As of 2019, I'm trying to follow a best practice on where to start observing LiveData in Fragments and if I should pass this or viewLifecycleOwner as a parameter to the observe() method.
According to this Google official documentation, I should observe in onActivityCreated() passing this (the fragment) as parameter.
According to this Google sample, I should observe in onViewCreated() passing viewLifecycleOwner as parameter.
According to this I/O video, I shouldn't use this but instead viewLifecycleOwner, but doesn't specify where should I start observing.
According to this pitfalls post, I should observe in onActivityCreated() and use viewLifecycleOwner.
So, where should I start observing? And should I either use this or viewLifecycleOwner?

If observing from an Activity you can observe on onCreate() and use this for the LifecycleOwner as stated here:
If you have a lifecycle-aware component that is hooked up to the lifecycle of your activity it will receive the ON_CREATE event. The method annotated with #OnLifecycleEvent will be called so your lifecycle-aware component can perform any setup code it needs for the created state.
Now if you are observing within a Fragment you can observe on onViewCreated() or onActivityCreated() and you should use getViewLifecycleOwner() and here is why:
Get a LifecycleOwner that represents the Fragment's View lifecycle. In most cases, this mirrors the lifecycle of the Fragment itself, but in cases of detached Fragments, the lifecycle of the Fragment can be considerably longer than the lifecycle of the View itself.

As in the I/O talk Yigit says, the Fragment and its view has different lifecycles. You would need to identify if your LiveData is related to the fragment or its view and pass the one desired. The compiler will accept both since both are implementations of LifecycleOwner

It doesn't matter whether you do it on onViewCreated or onActivityCreated. Both are called when the fragment is inflated, onViewCreated first, onActivityCreated afterwards. It's really a matter of preference.
The LiveData object takes a LifecycleOwner, and both Fragment and Activity implement the interface, so you just need to pass this.

Related

Why would a LiveData observed with viewLifecycleOwner get callbacks after onDestroyView?

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.

What should be lifeCycleOwner of LiveData-Fragment or Activity?

Will Activity be lifeCycleowner of LiveData?
or
Will Fragment be lifeCycleowner of LiveData?
The answer is as per my understanding and I would say, it depends on where LiveData is being used or called from?
Let's go through some basics.
LifecycleOwner by definition means
A class that has an Android lifecycle. These events can be used by custom components to handle lifecycle changes without implementing any code inside the Activity or the Fragment.
Lifecycle
Lifecycle-aware components perform actions in response to a change in the lifecycle status of another component, such as activities and fragments. These components help you produce better-organized, and often lighter-weight code, that is easier to maintain.
Since the Lifecycle of Activity and Fragments are different.
Activity - Activity has its own lifecycle
Fragment - Each Fragment instance has its own lifecycle. To manage the lifecycle, Fragment implements LifecycleOwner.
Fragments are basically contained inside an Activity; so if the Activity is destroyed, Fragments will also be destroyed.
But it's not necessary that if fragments are destroyed, Activity will also be destroyed.
Live Data
You can register an observer paired with an object that implements the LifecycleOwner interface. This relationship allows the observer to be removed when the state of the corresponding Lifecycle object changes to DESTROYED.
Now coming back to your question.
when LiveData is observed in Activity, the lifecycle owner is Activity itself.
when LiveData is observed in Fragment, the lifecycle owner is Fragment itself.
What should be lifeCycleOwner of LiveData-Fragment or Activity?
It really depends on where you're using liveData. LiveData is lifecycle-aware, which means they respect the lifecycle of android app components.
If you are using liveData to observe data inside activity, then you should observe using activity.
If you are using liveData to observe data inside a fragment, then there is no point in using activity as lifecycleOwner. Using activity would lead to a memory leak, if fragment is replaced or removed, as liveData would still hold a strong reference to the fragment, which will be kept until activity is destroyed.
We should use viewLifecycleOwner inside fragments, as they are bind to the lifecycle of fragments.
As stated in the Google documentation
Each Fragment instance has its own lifecycle. When a user navigates and interacts with your app, your fragments transition through various states in their lifecycle as they are added, removed, and enter or exit the screen.
So each fragment and activity have their own lifecycle.
When you observer LiveData in the fragment or activity you pass the lifecycleowner associated with that fragment or activity.

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.

getViewLifeCycleOwner() vs 'this' vs this.getActivity() in Androidx Fragments

We utilize LiveData's observe method quite a bit in our fragments. A recent release of the androidx fragment sdk is leading to Android Studio marking instances of liveDataObject.observe(this) as incorrect in favor of liveDataObject.observe(getViewLifecycleOwner()) .
Added a new Lint check that ensures you are using getViewLifecycleOwner() when observing LiveData from onCreateView(), onViewCreated(), or onActivityCreated(). (b/137122478)
https://developer.android.com/jetpack/androidx/releases/fragment
We are worried about implementing this change because we do not understand how the functionality of getViewLifecycleOwner() compares to that of using this, and whether it will cause a conflict with the use of this or this.getActivity() when setting up the ViewModel in the fragment.
Additionally, we use the Android Navigation component and noticed that when the user navigates to different fragments within the same activity, each fragment's onDestroyView() method is called, but not onDestroy()
Here is an example of our code in onViewCreated()
vm.getStemLengths().observe(this, stemLengths -> {
this.stemLengths = new ArrayList<>(Stream.of(stemLengths).map(stemLength ->
new SearchModel(Integer.toString(stemLength.getValue()))).toList());
});
Later, in onDestroyView()
vm.getStemLengths().removeObservers(this);
At the same time, depending on the fragment, the ViewModel that houses the LiveData is set up with one of the following:
vm = new ViewModelProvider(this.getActivity()).get(PrepareVM.class);
To persist the viewmodel across fragments in the activity.
Or:
vm = new ViewModelProvider(this).get(AprobacionVM.class);
If the VM does not need to be persisted outside of the current fragment
So to summarize, will changing this to getViewLifeCycleOwner() when observing LiveData objects in fragments' onCreateView() conflict with the ViewModel patterns / Navigation component? Could there be an instance for example where the livedata change ends up triggering an observer from a previous fragment in the same activity that a user navigates away from?
From the documentation of getViewLifeCycleOwner it seems that making this change may allow us to remove the removeObservers() call in each fragment's onDestroyView(). Is that the correct understanding?
Fragment implements LifecycleOwner which maps its create and destroy events to the fragment's onCreate and onDestroy, respectively.
Fragment.getViewLifecycleOwner() maps its create and destroy events to the fragment's onViewCreated and onDestroyView, respectively. The precise sequence is described here.
If you're working with views in your observers, you'll want the view lifecycle. Otherwise you might get updates when the view hierarchy is invalid, which may lead to crashes.
From the documentation of getViewLifeCycleOwner it seems that making this change may allow us to remove the removeObservers() call in each fragment's onDestroyView().
Correct.
There is already a bug with it. If you do a new Intent for a fragment already use it gives getView is null error. Why? The activity is newly creared.

Are there any reasons to ever scope LiveData to a fragment's lifecycle, rather than to the fragment's view's lifecycle?

If we scope LiveData to the lifecycle of a fragment by passing this to the observe method, the fragment doesn't get immediate updates if it is only detached from the activity, but not removed, because only the view is destroyed, not the fragment instance itself.
Instead, we can scope LiveData to the lifecycle of the view of the fragment, by calling observe in onActivityCreated and passing getViewLifecycleOwner() rather than this.
Is there any reason to not scope the LiveData to the fragment's view?
If your fragment does not have a UI then you will need to scope it with fragment's lifecycle.
Many people/libraries used and still use headless(UI-Less) worker fragments to have lifecycle awareness to safely pass on asynchronously retrieved data (Network Call) to the UI. (Similar to what Loaders do)

Categories

Resources