zoukankan      html  css  js  c++  java
  • Android中Handler导致的内存泄露

    http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

    Consider the following code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class SampleActivity extends Activity {
    
      private final Handler mLeakyHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
          // ... 
        }
      }
    }
    

    While not readily obvious, this code can cause cause a massive memory leak. Android Lint will give the following warning:

    In Android, Handler classes should be static or leaks might occur.

    But where exactly is the leak and how might it happen? Let's determine the source of the problem by first documenting what we know:

    1. When an Android application first starts, the framework creates a Looper object for the application's main thread. ALooper implements a simple message queue, processing Message objects in a loop one after another. All major application framework events (such as Activity lifecycle method calls, button clicks, etc.) are contained insideMessage objects, which are added to the Looper's message queue and are processed one-by-one. The main thread'sLooper exists throughout the application's lifecycle.

    2. When a Handler is instantiated on the main thread, it is associated with the Looper's message queue. Messages posted to the message queue will hold a reference to the Handler so that the framework can callHandler#handleMessage(Message) when the Looper eventually processes the message.

    3. 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 where exactly is the memory leak? It's very subtle, but consider the following code as an example:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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 10 minutes.
        mLeakyHandler.postDelayed(new Runnable() {
          @Override
          public void run() { /* ... */ }
        }, 1000 * 60 * 10);
     
        // Go back to the previous Activity.
        finish();
      }
    }
    

    When the activity is finished, the delayed message will continue to live in the main thread's message queue for 10 minutes before it is processed. The message holds a reference to the activity's Handler, and the Handler holds an implicit reference to its outer class (the SampleActivity, in this case). This reference will persist until the message is processed, thus preventing the activity context from being garbage collected and leaking all of the application's resources. Note that the same is true with the anonymous Runnable class on line 15. Non-static instances of anonymous classes hold an implicit reference to their outer class, so the context will be leaked.

    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):

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    public class SampleActivity extends Activity {
    
      /**
       * Instances of static inner classes do not hold an implicit
       * reference 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 do not hold an implicit
       * reference to their outer class when they are "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 10 minutes.
        mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
        
        // Go back to the previous Activity.
        finish();
      }
    }
    

    The difference between static and non-static inner classes is subtle, but is something every Android developer should understand. What's the bottom line? Avoid using non-static inner classes in an activity if instances of the inner class could outlive the activity's lifecycle. Instead, prefer static inner classes and hold a weak reference to the activity inside.

  • 相关阅读:
    海居住证我们不得不说的实情![转]
    SQL Server 日期和时间函数
    RESTORE DATABASE命令还原SQLServer 2005 数据库
    asp.net 部署数据库、开始菜单、桌面快捷方式实例(下)
    Server Application Unavailable asp.net 解决办法
    半个月,除了上班时间,而其他时间都不上网,你可以吗?(网络的郁闷)
    唐朝疆域地图[中亚势力范围(公元660年
    偶的偶像 陈松伶写真集
    Sql Server 行转列学习 根据学生表、课程表、学生成绩表统计每个学生的各科成绩和他的总成绩、平均成绩
    DIV+CSS 布局一行两列,左列固定宽度,右列自适应宽度;设置最小宽度,窗口小的时候显示滚动条.
  • 原文地址:https://www.cnblogs.com/ttylinux/p/4257758.html
Copyright © 2011-2022 走看看