8

I'm playing with rxjava and found there is a risk of memory leak if a subscription is not completed before an activity is destroyed because "observables retain a reference to the context". One of the demos for such case is given as below, if the subscription is not unsubscribed onDestroyed (source: https://github.com/dlew/android-subscription-leaks/blob/master/app/src/main/java/net/danlew/rxsubscriptions/LeakingActivity.java):

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_leaking);

    // This is a hot Observable that never ends;
    // thus LeakingActivity can never be reclaimed
    mSubscription = Observable.interval(1, TimeUnit.SECONDS)
        .subscribe(new Action1<Long>() {
            @Override public void call(Long aLong) {
                Timber.d("LeakingActivity received: " + aLong);
            }
        });
}

However I'm not sure why such a leak exists. I've checked the Observable class and seen nothing relevant to Context. So all I can think of is because there is an anonymous Action1 class defined within the subscribe method which hold a reference to the activity instance. And the observable in turn holds a reference to the action. Am I right?

Thanks

H.Nguyen
  • 1,621
  • 5
  • 19
  • 31
  • FYI, I created a plugin that shows up a list of leaked Disposable subscriptions in a detailed HTML report. Post on Medium: [Detect Leaked Subscriptions in RxJava code using RxDisposableWatcher](https://andrey-fomenkov.medium.com/find-leaked-subscriptions-in-rxjava-code-using-rxdisposablewatcher-8c2226dce01c) – Andrey Fomenkov Jan 13 '21 at 08:34

1 Answers1

3

The .subscribe(new Action1<Long>() { }) creates and stores nested class which as any non-static nested class has reference to containg class instance - in this case the Activity.

To resolve that you can Subscription.unsubscribe the mSubscription in the Activity.onDestroy

miensol
  • 39,733
  • 7
  • 116
  • 112