1234567 1234567 - 2 years ago 58
Android Question

Can using context in helper class cause memory leak in android

Can using context in helper class cause memory leak in android

I have a helper class with the following method

public class HelperClass {
private Context context;

public HelperClass(Context context) {
this.context = context;
}
public void Addfiles(Context context, String Filename) {
try {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(Filename);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
}


In my MainActivity I want to call it like this

public class MyActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
HelperClass h = new HelperClass(this);
h.Addfiles(this,Filename);
}
}


I want to know can using context like this cause memory leaks , and if so , how to deal with it.

Answer Source

TL;DR - strictly in the case above, no, since MyActivity won't be destroyed while in "onCreate"

Long answer:

Typically memory leaks happen when an object cannot be garbage collected because something still references it, when the garbage collector runs. In your case, the activity is just being created, and your primary concern is whether leaks can occur, since HelperClass holds a reference to it.

First of all, in normal conditions (excepting when AOS might kill your app) MainActivity is guaranteed to not get garbage collected before its onDestroy method will be called. This is because until then (and possibly for some time after that - not really relevant) it will be referenced by the Android Framework itself.

HelperClass on the other hand, is a local variable inside onCreate. After onCreate will finish, HelperClass might be garbage collected at any point, since it won't have any object referencing it (see here). So the chances of HelperClass being GC'd before onDestroy is called are quite high. If this happens then there will be no reference to MainActivity --> no leaks.

Event if HelperClass won't be garbage collected until onDestroy is called on MainActivity, you still won't have leaks since the garbage collector is smart enough to be able to clean up cyclic references.

What needs to happen for leaks to occur is that an object which outlives your Activity will hold a reference to it, or its context.

Assume your code would be like this:

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

    final HelperClass h = new HelperClass(this);

    //does some work on a background thread, gets notified at some 
    //point in the future, through the callback, when the work 
    //has completed     
    longLivedComponent.doSomeBackgroundWork(new OnWorkFinishedListener(){

        @Override
        public void onWorkFinished(){
            h.Addfiles(this, filename);
        }

    });
}

Now, let's also assume the following sequence of events:

  1. User opens app, MainActivity#1 is created, its onCreate is called
  2. doSomeBackgroundWork is called, background work is started. When the background work finishes, your helper (which has a reference to MainActivity#1) will have to do some work.
  3. User rotates device, an orientation change occurs.
  4. MainActivity is recreated by Android. MainActivity#1 is destroyed (i.e. onDestroy will be called), and a new MainActivity#2 will be created
  5. Steps 1,2 will happen for MainActivity#2 i.e. doSomeBackgroundWork will be called again, from MainActivity#2. (strictly speaking, this step isn't really relevant, but nevertheless)
  6. The Garbage Collector runs.
  7. The background work started by MainActivity#1 at step #2 finishes.

Normally, at step #6 the memory occupied by MainActivity#1 would be freed, as MainActivity#1 was destroyed.

However, in situation described here, the OnWorkFinishedListener needs to be persisted by longLivedComponent until the background work finishes. The listener has a reference to both your MainActivity#1 (implicit anonymous inner class reference to its parent class), and to your HelperClass instance, which also contains an instance to MainActivity#1.

When the garbage collector sees this at step #6, it assumes that MainActivity#1 is still alive & used since there stil are objects pointing to it. Because of this, it doesn't reclaim its memory, you'll end up with two instances of MainActivity in memory and a leak occurs.

To prevent this, you could:

  • Use the application context instead of the activity context, in classes that will be used by long-lived objects. Also, in your case you don't need anything specific to the activity itself
  • Make sure that any long-lived objects (like longLivedComponent in our case), or objects shared between activities, won't store references to an Activity or its Context, after onDestroy() has been called on said Activity

Hope this helps

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download