This Handler class should be static or leaks might

2019-04-08 14:38发布

问题:

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()!

回答1:

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 void getHandler() {
    return new MyHandler(this);
  }
}


回答2:

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



回答3:

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.