Friday, October 12, 2018

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

Leave a Comment

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

  1. LiveData fails to trigger callback.
  2. 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?

3 Answers

Answers 1

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 !

Answers 2

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.

Answers 3

To track every memory leak in your app and find out what's causing it you can try out this library github.com/square/leakcanary

its really useful tool and easy to use.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment