欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android中Handler引起的內(nèi)存泄露問(wèn)題解決辦法

 更新時(shí)間:2015年01月16日 09:17:30   投稿:junjie  
這篇文章主要介紹了Android中Handler引起的內(nèi)存泄露問(wèn)題解決辦法,本文講解了導(dǎo)致內(nèi)存泄露的情景,并給出了修改后的代碼,需要的朋友可以參考下

在Android常用編程中,Handler在進(jìn)行異步操作并處理返回結(jié)果時(shí)經(jīng)常被使用。通常我們的代碼會(huì)這樣實(shí)現(xiàn)。

復(fù)制代碼 代碼如下:

public class SampleActivity extends Activity {

  private final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // ...
    }
  }
}

但是,其實(shí)上面的代碼可能導(dǎo)致內(nèi)存泄露,當(dāng)你使用Android lint工具的話(huà),會(huì)得到這樣的警告

復(fù)制代碼 代碼如下:

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

看到這里,可能還是有一些搞不清楚,代碼中哪里可能導(dǎo)致內(nèi)存泄露,又是如何導(dǎo)致內(nèi)存泄露的呢?那我們就慢慢分析一下。

1.當(dāng)一個(gè)Android應(yīng)用啟動(dòng)的時(shí)候,會(huì)自動(dòng)創(chuàng)建一個(gè)供應(yīng)用主線(xiàn)程使用的Looper實(shí)例。Looper的主要工作就是一個(gè)一個(gè)處理消息隊(duì)列中的消息對(duì)象。在Android中,所有Android框架的事件(比如Activity的生命周期方法調(diào)用和按鈕點(diǎn)擊等)都是放入到消息中,然后加入到Looper要處理的消息隊(duì)列中,由Looper負(fù)責(zé)一條一條地進(jìn)行處理。主線(xiàn)程中的Looper生命周期和當(dāng)前應(yīng)用一樣長(zhǎng)。

2.當(dāng)一個(gè)Handler在主線(xiàn)程進(jìn)行了初始化之后,我們發(fā)送一個(gè)target為這個(gè)Handler的消息到Looper處理的消息隊(duì)列時(shí),實(shí)際上已經(jīng)發(fā)送的消息已經(jīng)包含了一個(gè)Handler實(shí)例的引用,只有這樣Looper在處理到這條消息時(shí)才可以調(diào)用Handler#handleMessage(Message)完成消息的正確處理。

3.在Java中,非靜態(tài)的內(nèi)部類(lèi)和匿名內(nèi)部類(lèi)都會(huì)隱式地持有其外部類(lèi)的引用。靜態(tài)的內(nèi)部類(lèi)不會(huì)持有外部類(lèi)的引用。關(guān)于這一內(nèi)容可以查看細(xì)話(huà)Java:”失效”的private修飾符

確實(shí)上面的代碼示例有點(diǎn)難以察覺(jué)內(nèi)存泄露,那么下面的例子就非常明顯了

復(fù)制代碼 代碼如下:

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();
  }
}

分析一下上面的代碼,當(dāng)我們執(zhí)行了Activity的finish方法,被延遲的消息會(huì)在被處理之前存在于主線(xiàn)程消息隊(duì)列中10分鐘,而這個(gè)消息中又包含了Handler的引用,而Handler是一個(gè)匿名內(nèi)部類(lèi)的實(shí)例,其持有外面的SampleActivity的引用,所以這導(dǎo)致了SampleActivity無(wú)法回收,進(jìn)行導(dǎo)致SampleActivity持有的很多資源都無(wú)法回收,這就是我們常說(shuō)的內(nèi)存泄露。

注意上面的new Runnable這里也是匿名內(nèi)部類(lèi)實(shí)現(xiàn)的,同樣也會(huì)持有SampleActivity的引用,也會(huì)阻止SampleActivity被回收。

要解決這種問(wèn)題,思路就是不適用非靜態(tài)內(nèi)部類(lèi),繼承Handler時(shí),要么是放在單獨(dú)的類(lèi)文件中,要么就是使用靜態(tài)內(nèi)部類(lèi)。因?yàn)殪o態(tài)的內(nèi)部類(lèi)不會(huì)持有外部類(lèi)的引用,所以不會(huì)導(dǎo)致外部類(lèi)實(shí)例的內(nèi)存泄露。當(dāng)你需要在靜態(tài)內(nèi)部類(lèi)中調(diào)用外部的Activity時(shí),我們可以使用弱引用來(lái)處理。另外關(guān)于同樣也需要將Runnable設(shè)置為靜態(tài)的成員屬性。注意:一個(gè)靜態(tài)的匿名內(nèi)部類(lèi)實(shí)例不會(huì)持有外部類(lèi)的引用。 修改后不會(huì)導(dǎo)致內(nèi)存泄露的代碼如下:

復(fù)制代碼 代碼如下:

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();
  }
}

其實(shí)在Android中很多的內(nèi)存泄露都是由于在Activity中使用了非靜態(tài)內(nèi)部類(lèi)導(dǎo)致的,就像本文提到的一樣,所以當(dāng)我們使用時(shí)要非靜態(tài)內(nèi)部類(lèi)時(shí)要格外注意,如果其實(shí)例的持有對(duì)象的生命周期大于其外部類(lèi)對(duì)象,那么就有可能導(dǎo)致內(nèi)存泄露。個(gè)人傾向于使用文章的靜態(tài)類(lèi)和弱引用的方法解決這種問(wèn)題。

相關(guān)文章

  • Java多線(xiàn)程工具CompletableFuture詳解

    Java多線(xiàn)程工具CompletableFuture詳解

    這篇文章主要介紹了Java多線(xiàn)程工具CompletableFuture詳解,CompletableFuture?是?java?1.8?追加的新特性,通俗的話(huà)來(lái)說(shuō),是一個(gè)函數(shù)式的,用于控制多任務(wù)同步、異步組合操作的工具,需要的朋友可以參考下
    2024-01-01
  • Springboot之idea之pom文件圖標(biāo)不對(duì)問(wèn)題

    Springboot之idea之pom文件圖標(biāo)不對(duì)問(wèn)題

    這篇文章主要介紹了Springboot之idea之pom文件圖標(biāo)不對(duì)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • springboot各種下載文件的方式匯總

    springboot各種下載文件的方式匯總

    下載功能其實(shí)就是用戶(hù)輸入指定文件路徑信息,然后把文件返回給用戶(hù),下面這篇文章主要給大家介紹了關(guān)于springboot各種下載文件的方式,需要的朋友可以參考下
    2022-10-10
  • 使用Maven將springboot工程打包成docker鏡像

    使用Maven將springboot工程打包成docker鏡像

    這篇文章主要介紹了使用Maven將springboot工程打包成docker鏡像,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java AES加密和解密教程

    Java AES加密和解密教程

    這篇文章主要介紹了Java AES加密和解密的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-12-12
  • Java實(shí)現(xiàn)數(shù)據(jù)更新和事件通知的觀察者模式

    Java實(shí)現(xiàn)數(shù)據(jù)更新和事件通知的觀察者模式

    Java觀察者模式是一種行為型設(shè)計(jì)模式,用于實(shí)現(xiàn)對(duì)象間的一對(duì)多依賴(lài)關(guān)系。當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),它的所有依賴(lài)對(duì)象都會(huì)收到通知并自動(dòng)更新。觀察者模式可以實(shí)現(xiàn)松耦合,增強(qiáng)了系統(tǒng)的可維護(hù)性和可拓展性
    2023-04-04
  • Struts2 文件上傳進(jìn)度條的實(shí)現(xiàn)實(shí)例代碼

    Struts2 文件上傳進(jìn)度條的實(shí)現(xiàn)實(shí)例代碼

    本篇文章主要介紹了Struts2 文件上傳進(jìn)度條的實(shí)現(xiàn)實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Springboot允許logger.debug輸出日志方式

    Springboot允許logger.debug輸出日志方式

    這篇文章主要介紹了Springboot允許logger.debug輸出日志方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Spring的RedisTemplate存儲(chǔ)的key和value有特殊字符的處理

    Spring的RedisTemplate存儲(chǔ)的key和value有特殊字符的處理

    這篇文章主要介紹了Spring的RedisTemplate存儲(chǔ)的key和value有特殊字符的處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 基于Session的國(guó)際化實(shí)現(xiàn)方法

    基于Session的國(guó)際化實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇基于Session的國(guó)際化實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08

最新評(píng)論