Search code examples
javaandroidandroid-activityweak-references

Best practice: weak reference to activity in static method


I need to reference an activity in several static methods. I'm curious to know the best practices to avoid memory leaks. Let's use examples:

Example 1:

static void hideKeyboard(Activity activity) {
   WeakReference<Activity> activityReference = new WeakReference<>(activity);
   // ... Call activityReference.get() when needed, check if null...
}

Example 2:

static void hideKeyboard(WeakReference<Activity> activityReference) {
   // ... Call activityReference.get() when needed, check if null...
}

So three questions:

  1. Do example 1 or 2 make any difference?
  2. I haven't seen methods being called this way much outside of subclasses of Thread or AsyncTask. Any reason why? Am I missing something?
  3. If the weak reference is used in a Thread or AsyncTask inside one of those methods, could memory still leak?

Solution

  • No, it doesn't make a difference. Garbage collection in Java works on the idea of GC roots. If a variable is a GC root or references by a GC root (including transitively) it cannot be garbage collected. Parameters to a function are a GC root- until the function returns none of its parameters can be collected. Since Activity is a parameter to your function, it will be uncollectable as long as that function is in the call stack. Using a WeakReference won't speed it up.

    Threads and AsyncTasks (which are just wrappers around Thread really) are slightly different. Every running thread is also a GC root. But threads can have a long lifetime and exist beyond the lifecycle of the object. Here, using a WeakReference does possibly help because there isn't another reason it needs to be kept around (like the parameter in your sample).

    Your example 2 is a bit better, it isn't blatantly unnecessary. But I question why its needed. In general when doing a Thread the pattern should be:

    run() {
       do_async_work()
       update_ui()
    }
    
    update_ui() {
      Activity activity = weakReference.get()
      if(activity == null) {
         return
      }
    
      //update the UI
    }
    

    Doing it like this will prevent a lot of problems like needing to check the weak reference a dozen times.