[android] This Handler class should be static or leaks might occur: IncomingHandler

I'm developing an Android 2.3.3 application with a service. I have this inside that service to communicate with Main activity:

public class UDPListenerService extends Service
{
    private static final String TAG = "UDPListenerService";
    //private ThreadGroup myThreads = new ThreadGroup("UDPListenerServiceWorker");
    private UDPListenerThread myThread;
    /**
     * Handler to communicate from WorkerThread to service.
     */
    private Handler mServiceHandler;

    // Used to receive messages from the Activity
    final Messenger inMessenger = new Messenger(new IncomingHandler());
    // Use to send message to the Activity
    private Messenger outMessenger;

    class IncomingHandler extends Handler
    {
        @Override
        public void handleMessage(Message msg)
        {
        }
    }

    /**
     * Target we publish for clients to send messages to Incoming Handler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());
    [ ... ]
}

And here, final Messenger mMessenger = new Messenger(new IncomingHandler());, I get the following Lint warning:

This Handler class should be static or leaks might occur: IncomingHandler

What does it mean?

The answer is


Here is a generic example of using a weak reference and static handler class to resolve the problem (as recommended in the Lint documentation):

public class MyClass{

  //static inner class doesn't hold an implicit reference to the outer class
  private static class MyHandler extends Handler {
    //Using a weak reference means you won't prevent garbage collection
    private final WeakReference<MyClass> myClassWeakReference; 

    public MyHandler(MyClass myClassInstance) {
      myClassWeakReference = new WeakReference<MyClass>(myClassInstance);
    }

    @Override
    public void handleMessage(Message msg) {
      MyClass myClass = myClassWeakReference.get();
      if (myClass != null) {
        ...do work here...
      }
    }
  }

  /**
   * An example getter to provide it to some external class
   * or just use 'new MyHandler(this)' if you are using it internally.
   * If you only use it internally you might even want it as final member:
   * private final MyHandler mHandler = new MyHandler(this);
   */
  public Handler getHandler() {
    return new MyHandler(this);
  }
}

This way worked well for me, keeps code clean by keeping where you handle the message in its own inner class.

The handler you wish to use

Handler mIncomingHandler = new Handler(new IncomingHandlerCallback());

The inner class

class IncomingHandlerCallback implements Handler.Callback{

        @Override
        public boolean handleMessage(Message message) {

            // Handle message code

            return true;
        }
}

As others have mentioned the Lint warning is because of the potential memory leak. You can avoid the Lint warning by passing a Handler.Callback when constructing Handler (i.e. you don't subclass Handler and there is no Handler non-static inner class):

Handler mIncomingHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        // todo
        return true;
    }
});

As I understand it, this will not avoid the potential memory leak. Message objects hold a reference to the mIncomingHandler object which holds a reference the Handler.Callback object which holds a reference to the Service object. As long as there are messages in the Looper message queue, the Service will not be GC. However, it won't be a serious issue unless you have long delay messages in the message queue.


With the help of @Sogger's answer, I created a generic Handler:

public class MainThreadHandler<T extends MessageHandler> extends Handler {

    private final WeakReference<T> mInstance;

    public MainThreadHandler(T clazz) {
        // Remove the following line to use the current thread.
        super(Looper.getMainLooper());
        mInstance = new WeakReference<>(clazz);
    }

    @Override
    public void handleMessage(Message msg) {
        T clazz = mInstance.get();
        if (clazz != null) {
            clazz.handleMessage(msg);
        }
    }
}

The interface:

public interface MessageHandler {

    void handleMessage(Message msg);

}

I'm using it as follows. But I'm not 100% sure if this is leak-safe. Maybe someone could comment on this:

public class MyClass implements MessageHandler {

    private static final int DO_IT_MSG = 123;

    private MainThreadHandler<MyClass> mHandler = new MainThreadHandler<>(this);

    private void start() {
        // Do it in 5 seconds.
        mHandler.sendEmptyMessageDelayed(DO_IT_MSG, 5 * 1000);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case DO_IT_MSG:
                doIt();
                break;
        }
    }

    ...

}

I'm confused. The example I found avoids the static property entirely and uses the UI thread:

    public class example extends Activity {
        final int HANDLE_FIX_SCREEN = 1000;
        public Handler DBthreadHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                int imsg;
                imsg = msg.what;
                if (imsg == HANDLE_FIX_SCREEN) {
                    doSomething();
                }
            }
        };
    }

The thing I like about this solution is there is no problem trying to mix class and method variables.


I am not sure but you can try intialising handler to null in onDestroy()


Examples related to android

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How to implement a simple scenario the OO way My eclipse won't open, i download the bundle pack it keeps saying error log getting " (1) no such column: _id10 " error java doesn't run if structure inside of onclick listener Cannot retrieve string(s) from preferences (settings) strange error in my Animation Drawable how to put image in a bundle and pass it to another activity FragmentActivity to Fragment A failure occurred while executing com.android.build.gradle.internal.tasks

Examples related to memory-leaks

AngularJS - Does $destroy remove event listeners? Implementing IDisposable correctly Best way to increase heap size in catalina.bat file If a DOM Element is removed, are its listeners also removed from memory? Resource leak: 'in' is never closed android activity has leaked window com.android.internal.policy.impl.phonewindow$decorview Issue This Handler class should be static or leaks might occur: IncomingHandler possible EventEmitter memory leak detected performSelector may cause a leak because its selector is unknown How can I create a memory leak in Java?

Examples related to static-classes

This Handler class should be static or leaks might occur: IncomingHandler Static Classes In Java Java inner class and static nested class

Examples related to android-lint

What is "android:allowBackup"? Lint: How to ignore "<key> is not translated in <language>" errors? This Handler class should be static or leaks might occur: IncomingHandler Android Lint contentDescription warning

Examples related to android-handler

Stop handler.postDelayed() This Handler class should be static or leaks might occur: IncomingHandler Running code in main thread from another thread Handler vs AsyncTask vs Thread How to remove all callbacks from a Handler? cancelling a handler.postdelayed process