Clarification about LiveData's strong references in ViewModels - android

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.

Related

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.

How does the Android Viewmodel works internally, internal working of view model

How does the Android Viewmodel works internally?
How Viewmodel save the data when the activity gets destroyed and recreated when the device get rotated
View Model's Internal Wokring:
View Model:
View Model is a lifecycle awared class, designed to store and manage UI related data. It a main component in MVVM architecture.
When a view model is created, it is stored inside activity or fragment manager.
Benefits:
Lifecycle awared
Hold and share UI data
Survives in rotation and retains data
Here we can raise a question that how we can get same instance of view model when new instance of activity is created while rotating screen from portrait to landscape ?
Answer:
To create a viewmodel object, ViewModelProvider class is required.
ViewModelProvider is the utility class which is used to create the instance of viewmodel in the following way.
Create a ViewModelProvider instance
Get the desired viewmodel from the viewmodel provider object
Internally creation of ViewModelProvider required two parameters.
ViewModelStoreOwner: it is an interface.It has just one method which returns the
ViewModelStore.
Factory: It is a nested interface in the ViewModelProvider class and is used to manufacture viewmodel objects.
val viewModelProvider = ViewModelProvider(this)
val viewModelProvider2 = ViewModelProvider(this,viewModelFactory)
If the factory is not passed then the default factory is created. Custom factory can be created for the parameterized viewmodel.
So now we have instance of viewmodel provider,
Now let’s get our viewmodel object
val viewModelProvider = ViewModelProvider(this)
val viewModel = viewModelProvider.get(LoginViewModel::class.java)
As we can see, we simply just called the get(arg) method with the desired viewmodel class reference and our viewmodel object was created.
So all the magic happens in this get method
This method gets the canonical name of the viewmodel class,creates a key by appending DEFAULT_KEY then it calls the another get function which takes the key and viewmodel class reference
This method checks the viewmodel instance in the viewmodel store first.If the viewmodel instance is there in the viewmodelstore then it simply returns that instance .If viewmodel instance is not there then it uses the factory to create the new instance and saves that instance in viewmodel store and then it return the viewmodel instance.
This viewmodel store is linked to ViewModelStoreOwner so our activity/fragment has their own viewmodel store.
It is ViewModelStore which stores the viewmodel and is retained when the rotation occurs and which returns the same viewmodel instance in the new activity instance.
Interview Question : Viewmodel store is linked to activity / fragment and when in the process of rotation current instance is destroyed and new instance is created then how this ViewModelStore object is still the same?
Let’s know about this magic
ViewModelStoreOwner is an interface. ComponentActivity implements this interface.
In above implementation , we can see that in the new activity object
when viewmodel store is null then it first checks with the
NonConfigurationInstance which returns the previous activity’s
viewmodel store.
If activity is being created for the first time then always new
viewmodel store objects will be created.
So It is NonConfigurationInstance object which is passed from old destroyed activity to newly created activity when rotations happens.It contains all the non-configuration related information including viewmodel store which contains the viewmodel of old activity object.
Answer is inspired by This Link
How does the Android Viewmodel works internally?
Android's ViewModel is designed to store and manage UI-related data in such a way that it can survive configuration changes such as screen rotations.
ViewModel gets called by an activity that previously called it, it re-uses the instance of that ViewModel object. However, if the Activity gets destroyed or finished, counterpart ViewModel calls the onClear() method for clearing up resources. Meaning if you have added something like this to your ViewModel:
override fun onClear() {
super.onClear()
clearAllLiveDataValues()
disposeAllVariables()
}
Function calls added here will be invoked.
How Viewmodel save the data when the activity gets destroyed and recreated when the device get rotated
ViewModel has its own lifecycle that allows itself to recover its state, and the transient data it holds, during screen rotations.
NOTE: Activity and ViewModel's lifecycle are both ephemeral. Allowing the ViewModel to handle critical or sensitive data during configuration changes IS NOT RECOMMENDED.
Your application should use either shared prefs, secured storage (if necessary), local database or cloud storage when you are expected to handle critical or sensistive data in a specific screen or part of your app.
I recommend that you read the following:
https://developer.android.com/topic/libraries/architecture/viewmodel
https://android.jlelse.eu/android-architecture-components-a563027632ce
https://medium.com/androiddevelopers/viewmodels-persistence-onsaveinstancestate-restoring-ui-state-and-loaders-fc7cc4a6c090

LiveData observing in Fragment

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.

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

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.

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.

Categories

Resources