handler1
is a leak.
I want to convert handler1
code to handler2
code. Is that OK?
What is the difference between the two codes?
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// leaks!
Handler handler1 = new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("LOG", "Hello~1");
}
};
Handler handler2 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.e("LOG", "Hello~2");
return false;
}
});
handler1.postDelayed(new Runnable() {
@Override
public void run() { }
}, 60000);
handler2.postDelayed(new Runnable() {
@Override
public void run() { }
}, 60000);
finish();
}
}
For the reason on leak warning, this article explains very well.
Quoting from the article
In Java, non-static inner and anonymous classes hold an implicit reference to their outer class. Static inner classes, on the other hand, do not.
So when you created handler1
by anonymous class, it will holds a reference to the MainActivity
instance and MainActiviy
can not be garbage collected.
Quoting from the article again
To fix the problem, subclass the Handler in a new file or use a static inner class instead. Static inner classes do not hold an implicit reference to their outer class, so the activity will not be leaked. If you need to invoke the outer activity’s methods from within the Handler, have the Handler hold a WeakReference to the activity so you don’t accidentally leak a context. To fix the memory leak that occurs when we instantiate the anonymous Runnable class, we make the variable a static field of the class (since static instances of anonymous classes do not hold an implicit reference to their outer class):
Following the article, update your code as follows:
public class MainActivity extends AppCompatActivity {
private static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("LOG", "Hello~1");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Handler handler1 = new MyHandler();
handler1.postDelayed(new Runnable() {
@Override
public void run() { }
}, 60000);
finish();
}
}
The answer from @Michael This Handler class should be static or leaks might occur: IncomingHandler provides the solution.
Quoting from @Michael answer
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.
In your case, handler2
will hold a reference to Handler.Callback
object.And since Handler.Callback
is created by anonymous class, hence it will hold a reference to MainActiviy
instance too. So MainActiviy
instance can not be garbage collected also.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With