Reprint Please specify source:http://blog.csdn.net/allen315410/article/details/43638373
This article is translated from: A foreign developer's blog How to Leak a context:handlers & Inner Classes, English can be a friend can directly click on the original view.
In Android common programming, handler is often used when asynchronous operations are performed and the returned results are processed. Usually our code will do that.
public class Sampleactivity extends Activity { private final Handler Mleakyhandler = new Handler () { @Override
public void Handlemessage (Message msg) { //...}}
However, the above code can lead to memory leaks, and when you use the Android Lint tool, you get this warning
This Handler class should be static or leaks might occur (com.example.multifragment.sampleactivity.1) issue:ensures that Handle R classes do don't hold on to a reference to an outer classid:handlerleaksince this Handler are declared as an inner class, It may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread and other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follow S:declare the Handler as a static class; In the outer class, instantiate a weakreference to the outer class and pass this object to your Handler when you Instantia Te the Handler; Make all references to the outer class using the WeakReference object.
See here, there may be some confusing, where in the code can lead to memory leaks, and how to cause memory leaks? Let's analyze it slowly.
1. When an Android app starts, it automatically creates a Looper instance that is used by the main thread. The main job of Looper is to handle a message object in a message queue. In Android, all Android frame events (such as activity lifecycle method calls and button clicks) are put into the message and then added to the message queue that looper to process, and the looper is responsible for processing one line at a time. The Looper life cycle in the main thread is as long as the current application.
2. When a handler is initialized on the main thread, we send a target for this handler message to the Looper processing message queue, and the message that has actually been sent already contains a reference to the handler instance. Only then Looper can call Handler#handlemessage (message) to complete the correct handling of the message when it is processed to this message.
3. In Java, non-static inner classes and anonymous inner classes implicitly hold references to their external classes. Static inner classes do not hold references to external classes.
It is true that the above code example is a bit difficult to detect a memory leak, so the following example is very obvious
public class Sampleactivity extends Activity { private final Handler Mleakyhandler = new Handler () { @Override
public void Handlemessage (Message msg) { //... } } @Override protected void onCreate (Bundle savedinstancestate) { super.oncreate (savedinstancestate); Post a message and delay its execution for ten minutes. Mleakyhandler.postdelayed (New Runnable () { @Override public void Run () {/* ... */} }, + *);
//Go back to the previous Activity. Finish (); }}
After analyzing the code above, when we perform the activity's finish method, the deferred message will be present in the main thread message queue for 10 minutes before it is processed, and the message contains the handler reference, and handler is an instance of an anonymous inner class. It holds a reference to the outside of the sampleactivity, so this causes the sampleactivity not to be recycled, which leads to sampleactivity holding a lot of resources that cannot be recycled, which is what we often call a memory leak.
Note that the above new runnable is also implemented in the anonymous inner class, which also holds the sampleactivity reference and prevents Sampleactivity from being recycled.
To solve this problem, the idea is not applicable to non-static inner classes, when inheriting handler, either in a separate class file, or using static internal classes. Because static inner classes do not hold references to external classes, they do not cause memory leaks for external class instances. When you need to invoke external activity in a static inner class, we can use a weak reference to handle it. Also on the same need to set runnable to static member properties. Note: A static anonymous inner class instance does not hold a reference to an external class. The code that will not cause a memory leak after modification is as follows
public class Sampleactivity extends Activity {/** * Instances of static inner classes does not hold a implicit * refe Rence to their outer class. */private static class MyHandler extends Handler {private final weakreference<sampleactivity> mactivity; Public MyHandler (sampleactivity activity) {mactivity = new weakreference<sampleactivity> (activity); } @Override public void Handlemessage (Message msg) {sampleactivity activity = mactivity.get (); if (activity! = NULL) {//...} }} private final MyHandler Mhandler = new MyHandler (this); /** * Instances of anonymous classes does not hold a implicit * reference to their outer class when they is "static". */private static final Runnable srunnable = new Runnable () {@Override public void run () {/* ... */}}; @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Post a message and delay its executioN for ten minutes. Mhandler.postdelayed (srunnable, 1000 * 60 * 10); Go back to the previous Activity. Finish (); }}
In fact, many of the memory leaks in Android are caused by the use of non-static internal classes in the activity, as mentioned in this article, so when we use a non-static inner class, we should pay special attention to if its instance holds the object life cycle is greater than its outer class object, Then it is possible to cause a memory leak. Individuals tend to use static classes of articles and weak references to solve this problem.
Memory leaks caused by using handler in Android