使用Handler导致内存泄露的解决方案

常说Android的Handler非静态内部类持有外部Activity的引用会造成内存泄露

原因是究竟什么?

private Handler handler = new Handler() {
      public void handleMessage(android.os.Message msg) {
          doSomeWork();
      }
 };

1)当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用(不然你怎么可能通过Handler来操作Activity中的View?)。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。

2)另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。

如何解决?

1.AndroidStudio提示的方法

This Handler class should be static or leaks might occur (anonymous android.os.Handler) less... (Ctrl+F1) Since this Handler is 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 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 follows: 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 instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

改为静态内部类定义Handler,并使用WeakReference持有外部Activity,与Activity交互

    private static class MyHandler extends Handler{

        private WeakReference mMyActivity;
        public MyHandler(MainActivity activity) {
            mMyActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            final MainActivity activity = mMyActivity.get();
            if (activity != null) {
                activity.doSomeWork();
            }
        }
    };

    public void doSomeWork() {
        // do
    }
2.及时清除消息,从根源上解决MessageQueue -> Message -> Handler -> Activity的引用链
mHandler.removeCallbacksAndMessages(null);

你可能感兴趣的:(使用Handler导致内存泄露的解决方案)