Handler和內部類的正確用法


PS:本文摘抄自《Android高級進階》,僅供學習使用

  Android代碼中涉及線程間通信的地方經常會使用Handler,典型的代碼結構如下。

public class HandlerActivity extends Activity{
    //可能引入內存泄漏的用法
    private final Handler mLeakyHandler = new Handler(){
        @Orrvide
        public void handleMessage(Mesage msg){
            //...
        }
    };
}

  使用Android Lint分析這段代碼,會違反檢測項AndroidLintHandlerLeak,得到如下提示。

This Handler class should be static or leaks might occur.

  那么產生內存泄漏的原因可能是什么呢?我們知道,Handler是和Looper以及MessageQueue一起工作的,在Android中,一個應用啟動后,系統默認會創建一個為主線程服務的Looper對象,該Looper對象用於處理主線程的所有Message對象,它的生命周期貫穿於整個應用的生命周期。在主線程中使用的Handler都會默認綁定到這個Looper對象。在主線程中創建Handler對象,它會立即關聯到主線程Looper對象的MessageQueue,這時發送到MessageQueue中的Message對象都會只有這個Handler對象的引用,這樣在Looper處理消息時常能回調到Handler的handlerMessage方法。因此,如果Message還沒有被處理完成,那么Handler對象也就不會被垃圾回收。

  在上面的代碼中,將Handler的實例聲明為HandlerActivity類的內部類。而在Java語言中,非靜態內部匿名類會持有外部類的一個隱式的引用,這樣就可能會導致外部類無法被垃圾回收。因此,最終由於MessageQueue中Message還沒處理完成,就會持有Handler對象的引用,而非靜態的Handler對象會持有外部類HandlerActivity的引用,這個Activity無法被垃圾回收,從而導致內存泄漏。

  一個明顯的會引入內存泄漏的例子如下。

public class HandlerActivity extends Activity{
    //可能引入內存泄漏的用法
    private final Handler mLeakyHandler = new Handler(){
        @Orrivide
        public void handleMessage(Mesage msg){
            //...
        }
    };
    @Orrivide
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        //延遲5分鍾發送消息
        mLeakyHandler.postDelayed(new Runnable(){
            @Orrivide
            public void run(){/* ... */}
        }, 1000*60*5);
    }
}

  由於消息延長5分鍾,因此,當用戶進入這個Activity並退出后,在消息發送並處理完成之前,這個Activity是不會被系統回收的(系統內存確實不夠使用的情況例外)。

  如果解決呢。有兩個方案。

  • 在子線程中使用Handler,這時需要開發者自己創建一個Looper對象,這個Looper對象的生命周期同一般的Java對象,因此這種用法沒有問題。
  • 將Handler生命為靜態的內部類,前面說過,靜態內部類不會持有外部類的引用,英寸,野不會引起內存泄漏,經典用法的代碼如下。
public class HandlerAcitivity extends Activity{
	//聲明一個靜態的Handler內部類,並持有外部類的弱引用
	private static class InnerHandler extends Handler{
		private final WeakReference<HandlerAcitivity> mActivity;
		public InnerHandler(HandlerAcitivity activity){
			mActivity = new WeakReference<HandlerAcitivity>(activity);
		}
		@Override
		public void handleMessage(Message msg){
			HandlerAcitivity activity = mActivity.get();
			if(activity!=null){
				//...
			}
		}
	}
	private final InnerHandler mHandler = new InnerHandler(this);
	//靜態的匿名內部類不會持有外部類的引用
	private static final Runnable sRunnable = new Runnable(){
		@Override
		public void run(){
			//...
		}
	};
	@Override
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		//延遲5分鍾發送消息
		mHandler.postDelay(sRunnable, 1000*60*5);
	}
}

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM