Android應用開發—如何解決handler的警告:Handler Class Should be Static or Leaks Occur

轉自android handler的警告Handler Class Should be Static or Leaks Occur

在使用Handler更新UI的時候,我是這樣寫的:

public class SampleActivity extends Activity {private final Handler mLeakyHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO}}
}

看起來很正常的,但是 Android Lint 卻給出了警告:

This Handler class should be static or leaks might occur

意思是說:這個Handler必須是static的,否則就會引發內存泄露。

其實,對于這個問題,Android Framework 的工程師 Romain Guy 早已經在Google論壇上做出過解釋,并且給出了他的建議寫法:

I wrote that debugging code because of a couple of memory leaks I
found in the Android codebase. Like you said, a Message has a
reference to the Handler which, when it’s inner and non-static, has a
reference to the outer this (an Activity for instance.) If the Message
lives in the queue for a long time, which happens fairly easily when
posting a delayed message for instance, you keep a reference to the
Activity and “leak” all the views and resources. It gets even worse
when you obtain a Message and don’t post it right away but keep it
somewhere (for instance in a static structure) for later use.

他的建議寫法是:

class OuterClass {class InnerClass {private final WeakReference<OuterClass> mTarget;InnerClass(OuterClass target) {mTarget = new WeakReference<OuterClass>(target);}void doSomething() {OuterClass target = mTarget.get();if (target != null) {target.do();    }}
}

下面,我們進一步解釋一下:

  • Android App啟動的時候,Android Framework 為主線程創建一個Looper對象,這個Looper對象將貫穿這個App的整個生命周期,它實現了一個消息隊列(Message Queue),并且開啟一個循環來處理Message對象。而Framework的主要事件都包含著內部Message對象,當這些事件被觸發的時候,Message對象會被加到消息隊列中執行。
  • 當一個Handler被實例化時(如上面那樣),它將和主線程Looper對象的消息隊列相關聯,被推到消息隊列中的Message對象將持有一個Handler的引用以便于當Looper處理到這個Message的時候,Framework執行Handler的handleMessage(Message)方法。
  • 在 Java 語言中,非靜態匿名內部類將持有一個對外部類的隱式引用,而靜態內部類則不會。

到底內存泄露是在哪里發生的呢?以下面代碼為例:

public class SampleActivity extends Activity {              private final Handler mLeakyHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// ...}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Post a message and delay its execution for 10 minutes.mLeakyHandler.postDelayed(new Runnable() {@Overridepublic void run() { }}, 60 * 10 * 1000);// Go back to the previous Activity.finish();}
}

當Activity被finish()掉,Message將存在于消息隊列中長達10分鐘的時間才會被執行到。這個Message持有一個對Handler的引用,Handler也會持有一個對于外部類(SampleActivity)的隱式引用,這些引用在Message被執行前將一直保持,這樣會保證Activity的上下文不被垃圾回收機制回收,同時也會泄露應用程序的資源(views and resources)。

為解決這個問題,下面這段代碼中的Handler則是一個靜態匿名內部類。靜態匿名內部類不會持有一個對外部類的隱式引用,因此Activity將不會被泄露。如果你需要在Handler中調用外部Activity的方法,就讓Handler持有一個對Activity的WeakReference,這樣就不會泄露Activity的上下文了,如下所示:

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);}@Overridepublic 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() {@Overridepublic void run() { }};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Post a message and delay its execution for 10 minutes.mHandler.postDelayed(sRunnable, 60 * 10 * 1000);// Go back to the previous Activity.finish();}
}

總結:
在實際開發中,如果內部類的生命周期和Activity的生命周期不一致(比如上面那種,Activity finish()之后要等10分鐘,內部類的實例才會執行),則在Activity中要避免使用非靜態的內部類,這種情況,就使用一個靜態內部類,同時持有一個對Activity的WeakReference。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/450035.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450035.shtml
英文地址,請注明出處:http://en.pswp.cn/news/450035.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從遠程(包括ftp,http等協議)地址獲取文件流信息

URL url new URL("ftp://172.18.251.155:8010/recordsImg/2019-01-28/000008_1548649813267.jpg"); MultipartFile multipartFile new MockMultipartFile(fileName,fileName,"", url.openStream());轉載于:https://www.cnblogs.com/baihaojie/p/10331134…

shell 數組

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1&#xff09;定義數組&#xff1a; my_array(1 2 3 4) 也可這樣賦值&#xff1a;my_array[4]愛 讀取&#xff1a; echo ${my_array[2]…

nodejs 實現文件拷貝

通過4中不通的方式實現對一個文件的拷貝 方式一&#xff1a;readFile 異步一次性讀取文件再寫入 //異步形式讀取文件 function copyFile(url){const extName path.extname(url)const fileName path.basename(url)const dirName path.dirname(url)fs.readFile(url, (err, dat…

國家部委對4G調研:未定給中電信聯通發放牌照

一場有關4G牌照發放的論戰正在發酵&#xff0c;矛盾的核心在于&#xff0c;除了中移動外&#xff0c;政府是否也會向中電信和聯通發放TD-LTE(中國主導的4G標準)牌照 記者 王云輝 雍忠瑋 一場圍繞4G的新博弈已經白熱化。 “多個國家部委正在對4G展開全面調研&#xff0c;但最終如…

Luogu4735 最大異或和

題目藍鏈 Description 給你一個序列&#xff0c;你需要支持以下兩個操作&#xff1a; A x: 在序列尾部添加一個整數\(x\)&#xff0c;序列的長度增加\(1\)Q l r x: 詢問操作&#xff0c;你需要找到一個位置\(p \in [l, r]\)&#xff0c;使得&#xff1a;\(x \bigoplus a_p \big…

Spring-jdbc:JdbcTemplate使用簡介

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 為了使 JDBC 更加易于使用,Spring 在 JDBCAPI 上定義了一個抽象層, 以此建立一個JDBC存取框架. 作為 SpringJDBC 框架的核心, JDBC 模板…

Java多線程編程:變量共享分析(Thread)

Java多線程編程&#xff1a;變量共享分析&#xff08;Thread&#xff09; Java 創建線程的兩種方法 此處只簡單講下自己對java多線程變量共享的理解&#xff1a; 按照進程和多線程的原理&#xff0c;同一進程內的多個線程之間的地址空間是共享的&#xff08;除去ThreadLocal&a…

嘉益仕(Litns)帶您讀懂MES系統:選型篇

自從智能制造概念提出以來&#xff0c;制造執行系統MES在國內掀起了新一波的熱潮。眾多企業在技術發展、政策導向和自身需要的推動下&#xff0c;紛紛上馬MES請添加鏈接描述項目。 由此也帶動了MES軟件開發企業的快速發展。一夜之間MES軟件開發企業遍地開花&#xff0c;MES產品…

[WPF]xml序列化以及反序列化數據

代碼 XML序列化工具類 public static class XMLHelper{/// <summary>/// 將對象序列化為指定的文件名/// </summary>/// <typeparam name"T"></typeparam>/// <param name"obj"></param>/// <param name"fil…

多線程的那點兒事

1. 多線程的那點兒事&#xff08;基礎篇&#xff09; 多線程編程是現代軟件技術中很重要的一個環節。要弄懂多線程&#xff0c;這就要牽涉到多進程&#xff1f;當然&#xff0c;要了解到多進程&#xff0c;就要涉及到操作系統。不過大家也不要緊張&#xff0c;聽我慢慢道來。…

Android應用開發—AsyncTask

摘錄自 Android 多線程—–AsyncTask詳解 AsyncTask AsyncTask&#xff1a;異步任務&#xff0c;從字面上來說&#xff0c;就是在我們的UI主線程運行的時候&#xff0c;異步的完成一些操作。AsyncTask允許我們的執行一個異步的任務在后臺。我們可以將耗時的操作放在異步任務當…

std::shared_ptr之deleter的巧妙應用

本文由作者鄒啟文授權網易云社區發布。std::shared_ptr一次創建&#xff0c;多處共享&#xff0c;通過引用計數控制生命周期。 實例 在郵箱大師PC版中&#xff0c;我們在實現搜索時&#xff0c;大致思路是這樣的&#xff1a; 每一個賬號都有一個SearchFlow&#xff0c;搜索開始…

js - 執行上下文和作用域以及閉包

首先&#xff0c;咱們通常被"執行上下文"&#xff0c;"執行上下文環境"&#xff0c;"上下文環境"&#xff0c;"執行上下文棧"這些名詞搞混。那我們一一來揭秘這些名字的含義。 這一塊一直比較晦澀難懂&#xff0c;還是需要仔細去斟酌斟…

Spring之JDBCTemplate

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 一、Spring對不同的持久化支持&#xff1a; Spring為各種支持的持久化技術&#xff0c;都提供了簡單操作的模板和回調 ORM持久化技術模…

從螞蟻金服實踐入手,帶你深入了解 Service Mesh

本文整理自螞蟻金服高級技術專家敖小劍在 QCon 上海 2018 上的演講。我是來自螞蟻金服中間件團隊的敖小劍&#xff0c;目前是螞蟻金服 Service Mesh 項目的 PD。我同時也是 Servicemesher 中國技術社區的創始人&#xff0c;是 Service Mesh 技術在國內最早的布道師。我今天給大…

Android應用開發—FragmentManager如何管理fragments

本文主要摘錄自Android中使用FragmentManager管理fragments 和 淺談FragmentManager與fragment之一二事 先講下自己對fragment的理解&#xff1a; 對于fragment&#xff0c;有太多官方文檔和博文來介紹&#xff0c;此處不做轉述&#xff1a;我感覺android提供fragment這種組件…

數組指針 和 指針數組

最近發現公司有些人說怎樣區分 數組指針 和 指針數組 &#xff1f; 其實 很簡單&#xff1b; 數組指針&#xff0c; 先是&#xff08;定語 &#xff09; &#xff08;主體&#xff09;&#xff0c; &#xff08;定語 數組&#xff09; &#xff08;主體 指針&#xff09…

在云服務器上注意GeoServer和ShadowDataMap的跨域設置

在云服務器上注意GeoServer和ShadowDataMap的跨域設置 1、對于支持cors的網絡資源 可以在ShadowDataMap的devserverconfig.json里設置相應的跨域資源 提示&#xff1a;geoserver發布的地圖服務雖然同在一個服務器上&#xff0c;但是端口不一樣&#xff0c;同樣需要設置跨域 如&…

Guava ImmutableCollection簡介

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 ImmutableCollection代碼定義 GwtCompatible(emulatedtrue) public abstract class ImmutableCollection<E> extends AbstractCo…