Handler致使內存泄露分析

Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
            // do something.
    }
}
```
當咱們這樣建立`Handler`的時候`Android Lint`會提示咱們這樣一個`warning: In Android, Handler classes should be static or leaks might occur.`。       

一直以來沒有仔細的去分析泄露的緣由,先把主要緣由列一下:    
- `Android`程序第一次建立的時候,默認會建立一個`Looper`對象,`Looper`去處理`Message Queue`中的每一個`Message`,主線程的`Looper`存在整個應用程序的生命週期.
- `Hanlder`在主線程建立時會關聯到`Looper`的`Message Queue`,`Message`添加到消息隊列中的時候`Message(排隊的Message)`會持有當前`Handler`引用,當`Looper`處理到當前消息的時候,會調用`Handler#handleMessage(Message)`.就是說在`Looper`處理這個`Message`以前,會有一條鏈`MessageQueue -> Message -> Handler -> Activity`,因爲它的引用致使你的`Activity`被持有引用而沒法被回收`
- **在java中,no-static的內部類會隱式的持有當前類的一個引用。static的內部類則沒有。**

##具體分析
```java
public class SampleActivity extends Activity {

  private final Handler mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                  // do something
                }
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        // 發送一個10分鐘後執行的一個消息
        mHandler.postDelayed(new Runnable() {
          @Override
          public void run() { }
        }, 600000);

        // 結束當前的Activity
        finish();
}
```
在`finish()`的時候,該`Message`尚未被處理,`Message`持有`Handler`,`Handler`持有`Activity`,這樣會致使該`Activity`不會被回收,就發生了內存泄露.

##解決方法 
- 經過程序邏輯來進行保護。
    - 若是`Handler`中執行的是耗時的操做,在關閉`Activity`的時候停掉你的後臺線程。線程停掉了,就至關於切斷了`Handler`和外部鏈接的線,`Activity`天然會在合適的時候被回收。 
    - 若是`Handler`是被`delay`的`Message`持有了引用,那麼在`Activity`的`onDestroy()`方法要調用`Handler`的`remove*`方法,把消息對象從消息隊列移除就好了。 
            - 關於`Handler.remove*`方法
                        - `removeCallbacks(Runnable r)` ——清除r匹配上的Message。    
                        - `removeC4allbacks(Runnable r, Object token)` ——清除r匹配且匹配token(Message.obj)的Message,token爲空時,只匹配r。
                        - `removeCallbacksAndMessages(Object token)` ——清除token匹配上的Message。
                        - `removeMessages(int what)` ——按what來匹配     
                        - `removeMessages(int what, Object object)` ——按what來匹配      
                        咱們更多須要的是清除以該`Handler`爲`target`的全部`Message(Callback)`就調用以下方法便可`handler.removeCallbacksAndMessages(null)`;
- 將`Handler`聲明爲靜態類。
    靜態類不持有外部類的對象,因此你的`Activity`能夠隨意被回收。可是不持有`Activity`的引用,如何去操做`Activity`中的一些對象? 這裏要用到弱引用
        
```java
public class MyActivity extends Activity {
        private MyHandler mHandler;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                mHandler = new MyHandler(this);
        }

        @Override
        protected void onDestroy() {
                // Remove all Runnable and Message.
                mHandler.removeCallbacksAndMessages(null);
                super.onDestroy();
        }

        static class MyHandler extends Handler {
                // WeakReference to the outer class's instance.
                private WeakReference<MyActivity> mOuter;

                public MyHandler(MyActivity activity) {
                        mOuter = new WeakReference<MyActivity>(activity);
                }

                @Override
                public void handleMessage(Message msg) {
                        MyActivity outer = mOuter.get();
                        if (outer != null) {
                                // Do something with outer as your wish.
                        }
                }
        }
}java

相關文章
相關標籤/搜索