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.