Memory leak caused by Android development Handler

If you define an internal Handler class in Activity, the following code:

public class MainActivity extends Activity {
     
     
 
    private  Handler mHandler = new Handler() {
     
     
        @Override
        public void handleMessage(Message msg) {
     
     
            //TODO handle message...
        }
    };
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
     
     
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler.sendMessageDelayed(Message.obtain(), 60000);
 
        //just finish this activity
        finish();
    }
}

Then run the Android Lint tool and there will be a memory leak warning:

This Handler class should be static or leaks might occur (com.example.ta.MainActivity.1)
Issue: Ensures that Handler classes do not hold on to a reference to an outer class
Id: HandlerLeak
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.

The reason is:

  • When the Android application starts, it will first create a Looper object of the main thread of the application. Looper implements a simple message queue and processes the Message objects in it one by one. The Looper object of the main thread exists throughout the application life cycle.

  • When the Handler is initialized in the main thread, the Handler is associated with Looper's message queue. The Message sent to the message queue will reference the Handler object that sent the message, so that the system can call Handler#handleMessage(Message) to distribute and process the message.

  • In Java, non-static (anonymous) inner classes refer to outer class objects. The static inner class does not reference the outer class object.

  • If the external class is Activity, it will cause Activity to leak.

When Activity finishes, the delayed message will continue to exist in the main thread message queue for 1 minute, and then the message will be processed. The message refers to the Handler object of the Activity, and then the Handler refers to the Activity. These reference objects will remain until the message is processed, which will cause the Activity object to be unable to be recycled, which leads to the Activity leak mentioned above.

To fix this problem, just follow Lint's instructions to define the Handler class as static, and then use WeakReference to maintain the external Activity object.

private Handler mHandler = new MyHandler(this);
private static class MyHandler extends Handler{
     
     
    private final WeakReference<Activity> mActivity;
    public MyHandler(Activity activity) {
     
     
        mActivity = new WeakReference<Activity>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
     
     
        System.out.println(msg);
        if(mActivity.get() == null) {
     
     
            return;
        }
    }
}

Therefore, when you use an inner class in an Activity, you need to always consider whether you can control the life cycle of the inner class. If not, it is best to define a static inner class.

Reference article: http://blog.chengyunfeng.com/?p=468

Guess you like

Origin blog.csdn.net/xhf_123/article/details/50016555