LeakCanary - Activity is leaked as it implements SyncStatusObserver

731 views Asked by At

I am using LeakCanary to identify memory leaks. I have an Activity which adds itself as the StatusChangeObserver in onResume as below:

    final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
            ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;

    mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask, this);

And stops listening onPause

    ContentResolver.removeStatusChangeListener(mSyncObserverHandle);

When I exit the Activity, LeakCanary reports my Activity is leaked. Below is gist of the leak trace:

     * com.sample.android.MyListActivity has leaked:
     * GC ROOT android.content.ContentResolver$1.val$callback(anonymous class extends android.content.ISyncStatusObserver$Stub)
     * leaks com.sample.android.MyListActivity instance
     [ 06-11 15:35:23.123 11823:13392 D/LeakCanary ]
     * Reference Key: 1eaf447d-055c-4767-bb3f-56b12c7a4dae
     * Device: motorola motorola XT1022 condor_retaildsds
     * Android Version: 4.4.4 API: 19 LeakCanary: 1.3.1
     * Durations: watch=5029ms, gc=147ms, heap dump=693ms, analysis=15159ms
     [ 06-11 15:35:23.123 11823:13392 D/LeakCanary ]

I have tested on API 19 and 22. I would like to know if its a problem with my code or leakcanary or sdk.

Thanks in advance!

1

There are 1 answers

0
tsiro On

i have faced the same issue, after testing my app for memory issues or leaks using both the LeakCanary library and the Memory Analyzer Tool i found out that my SyncStatusObserver instance was leaking my Activity. From what i have understood about anonymous classes the most rational reason for this leak seems to be that anonymous classes implicity reference the containing Class if the are declared non static. So, i declared the mSyncStatusObserver as static(May not reference the containing class members without an explicit reference) and after testing again the leaks gone away

 private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {

    /** Callback invoked with the sync adapter status changes. */
    @Override
    public void onStatusChanged(int which) {
    ....
    }

in my onResume

protected void onResume() {
    super.onResume();
    mSyncStatusObserver.onStatusChanged(0);

    // Watch for sync state changes
    final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
            ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
    mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask, mSyncStatusObserver);
}

and in my onStop i removed the listener

 @Override
  protected void onStop() {
    super.onStop();
    if (mSyncObserverHandle != null) {
        ContentResolver.removeStatusChangeListener(mSyncObserverHandle);
        mSyncObserverHandle = null;
       // mSyncStatusObserver = null;
    }
}

i am new to Android development, i am not entirely sure if the explanation i offer is completely correct so if anyone has to offer a better solution is welcome