Memory Leak found by LeakCanary for AppOpsManager OnOpChangedListener callback Function

449 Views Asked by At

I am finding the available memory leaks in my Android application, LeakCanary always says that AppOpsManager OnOpChangedListener callback Function has Leaks for MainActivity. I searched a lot on google and SF but did not find any solution for this. Below is my code, Please help to solve this memory leak.

@Override
protected void onCreate(Bundle savedInstanceState) {    
    appOpsManager = (AppOpsManager) getApplicationContext().getSystemService(Context.APP_OPS_SERVICE);
    appOpsManager.startWatchingMode(AppOpsManager.OPSTR_GET_USAGE_STATS, getApplicationContext().getPackageName(), usageOpListener);
    }

private final AppOpsManager.OnOpChangedListener usageOpListener = new AppOpsManager.OnOpChangedListener() {
    @Override
    public void onOpChanged(String op, String packageName) {
        if (packageName == null || getApplicationContext().getPackageName().equals(packageName)) {
            if (AppOpsManager.OPSTR_GET_USAGE_STATS.equals(op)) {
                Intent myIntent = new Intent(getApplicationContext(), MainActivity.class);
                getApplicationContext().startActivity(myIntent);
            }
        }
    }
};

@Override
protected void onDestroy() {    
appOpsManager.stopWatchingMode(usageOpListener);
}
1

There are 1 best solutions below

1
Martin Marconcini On

I believe (although you haven't shown it) that the problem is:

  1. You register a local object to your instance (usageOpListener) to another object that you obtained indirectly through the system locator service (appOpsManager) during your class' onCreate.
  2. This reference to YourActivity#OnOpChangedListener is now a hard reference inside the AppOpsManager.
  3. You then expect the reference to go away when your activity is destroyed, but your activity is not always destroyed by the Framework. It can be stopped, but the hard reference to it, is still present in the AppOps Manager.

I'd move the start/stop watching code to onStart/onStop respectively.