Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

On below code Eclipse generate warning "This Handler class should be static or leaks might occur".

public class MyActivity extends Activity implements Runnable
 {
   final Handler handler = new Handler()
    {
      @Override
      public void handleMessage( Message message)
       {
         String sResult = (String) message.obj;
         if( (sResult != null) && (sResult != ""))
           {
             MyNonStatic = (TableLayout) findViewById( R.id.tableLayout); // any non-static method
           }
         return;
       }
    };


   public void run()
    {
      final Message message = handler.obtainMessage( 1, MyFunction( context));
      handler.sendMessage( message);
    }

   public String MyFunction( Context context)
    {
      return "MyNewString";
    }
  }

I review many topics on site, but not get solution. Please help me for this code?

Add: i need call non-static method (for example findViewById()) in handleMessage()!

like image 633
Tapa Save Avatar asked Nov 22 '12 06:11

Tapa Save


People also ask

Should handlers be static?

If handler is not static, your Service or Activity cannot be garbage collected, even after being destroyed. This may lead to memory leaks, for some time at least - as long as the messages stay int the queue.

What does handler mean in Java?

A Handler object takes log messages from a Logger and exports them. It might for example, write them to a console or write them to a file, or send them to a network logging service, or forward them to an OS log, or whatever. A Handler can be disabled by doing a setLevel(Level.

What is a Handler class?

As given in Handler documentation on android dev site, there are two main uses for a Handler: To schedule messages and runnables to be executed as some point in the future; and. To enqueue an action to be performed on a different thread than your own.

Which thread will process a message posted to a handler?

Android handles all the UI operations and input events from one single thread which is known as called the Main or UI thread. Android collects all events in this thread in a queue and processes this queue with an instance of the Looper class.


3 Answers

Here is an 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...
      }
    }
  }

  private final MyHandler mHandler = new MyHandler(this);

  public MyHandler getHandler() {
    return new MyHandler(this);
  }
}
like image 182
Sogger Avatar answered Oct 03 '22 11:10

Sogger


handler - Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.

Imagine the situation. Some Activity calls PendingIntent.send(...) and put the non-static inner subclass of Handler. And then activity is destroyed. But inner class lives.

Inner class still holds a link to destroyed activity, it cannot be garbage-collected.

And hence you need to make it static.

Source: Handlers and memory leaks in Android

like image 37
Shrikant Ballal Avatar answered Oct 03 '22 11:10

Shrikant Ballal


From Android lint checks:

HandlerLeak
-----------
Summary: Ensures that Handler classes do not hold on to a reference to an
outer class

Priority: 4 / 10
Severity: Warning
Category: Performance

In Android, Handler classes should be static or leaks might occur. Messages
enqueued on the application thread's MessageQueue also retain their target
Handler. If the Handler is an inner class, its outer class will be retained as
well. To avoid leaking the outer class, declare the Handler as a static nested
class with a WeakReference to its outer class.

First part of the warning is because final Handler handler = new Handler() creates an anonymous inner class. Inner classes can't be created in a standalone fashion, you always need an outer instance. Remember how you would create this in Java OuterClass.InnerClass innerObject = outerObject.new InnerClass();. Every inner class object also has to keep a reference to outer object Outer.this to access outer's members.

Second part is final Message message = handler.obtainMessage( 1, MyFunction( context)); has a handle to your inner handler class (which has a handler to outer Activity class). If this message lives long enough, it won't be possible to garbage collect your Activity.

What can block your message being processed? Unfortunately lint tool can't figure that out, so it always warns you about possible memory leak. If you are sure about what you are doing, you can suppress these messages by various methods.

For your case it doesn't look like a good idea to make Activity a Runnable but anyway may be you should use Handler.post or best Activity.runOnUIThread.

like image 45
auselen Avatar answered Oct 03 '22 10:10

auselen