Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android -) 如何避免Handler引起內存洩露

Android -) 如何避免Handler引起內存洩露

編輯:關於Android編程

 

錯誤代碼

如果在Activiy中通過內部類(Runnable)的方式定義了一個變量runnable,

final Runnable runnable = new Runnable() {
    public void run() {
        // ... do some work
    }
};
handler.postDelayed(runnable, TimeUnit.SECONDS.toMillis(10)

因為Runnable不是static類型,所以會有一個包含Activity實例的implicit reference --- Activity.this。

如果Activity在runnable變量run之前(10s內)被finish掉了但是Activity.this仍然存在,那麼Activity的對象就不會被GC回收,從而導致memory leak

即使使用一個靜態內部類,也不能保證萬事大吉。

static class MyRunnable implements Runnable {
    private View view;
    public MyRunnable(View view) {
        this.view = view;
    }
    public void run() {
        // ... do something with the view
    }
}

假設在runnable執行之前,View被移除了,但是成員變量view還在繼續引用它,仍然會導致memory leak

上面的兩個例子當中,導致內存洩露的兩種用法分別是隱式引用(implicit reference)顯式引用(explicit reference)

解決方法

解決隱式引用的方法比較簡單,只要使用內部非靜態類(non-static inner class)或者 top-level class(在一個獨立的java文件中定義的變量)就可以將隱式變為顯式,從而避免內存洩露。

如果繼續使用非靜態內部類,那麼就要在onPause的時候手動結束那些掛起的任務(pending task)。

關於如何結束任何,Handler可參考這篇文章中的Canceling a pending RunnableCanceling pending Messages。HandlerThread可參考這篇文章。

解決第二個問題要用到WeakReference,WeakReference的用法可以google一下,簡而言之就是:只要還有其他的stronger reference,WeakReference就可以繼續引用。

static class MyRunnable implements Runnable {
    private WeakReference>View< view;
    public MyRunnable(View view) {
        this.view = new WeakReference>View<(view);
    }
    public void run() {
        View v = view.get();
        if (v != null) {
            // ... do something with the view
        }
    }
}

這樣一來問題就解決了,美中不足的是每次使用view之前都要做空指針判斷。另外一個比較高效的方法就是在onResume中為runnable的view賦值,在onPause中賦值為null。

private static class MyHandler extends Handler {
    private TextView view;
    public void attach(TextView view) {
        this.view = view;
    }
    public void detach() {
        view = null;
    }
    @Override
    public void handleMessage(Message msg) {
        // ....
    }

總結

在繼承Handler或者HandlerThread的時候,

盡量定義一個static類或者top-level類。如果用到了ui元素,一定要在Activity的生命周期接觸之前釋放掉。

參考

Asynchronous Android - Steve Liles

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved