This Handler class should be static or leaks might occur Android警告处理

        更新到ADT2.0的开发者们可能会在handler上发现这么一条警告:This Handler class should be static or leaks might occur 。首先在ADT 20 Changes我们可以找到这样一个变化:New Lint Checks:Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its outer class.首先解释下这句话This Handler class should be static or leaks might occur,大致意思就是说:Handler类应该定义成静态类,否则可能导致内存泄露。

具体如何解决,在国外有人提出,如下:

Issue: Ensures that Handler classes do not hold on to a reference to an outer class 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.

大体翻译如下:

Handler 类应该应该为static类型,否则有可能造成泄露。在程序消息队列中排队的消息保持了对目标Handler类的应用。如果Handler是个内部类,那 么它也会保持它所在的外部类的引用。为了避免泄露这个外部类,应该将Handler声明为static嵌套类,并且使用对外部类的弱应用。


解决方式一  推荐使用,比较适合

这里我们可以采用弱引用的方式来解决问题,我们先定义一个static的内部类CHandler ,然后让它持有Activity的弱引用,这样问题就得到了解决。

static class CHandler extends Handler{
	
	WeakReference<AsBindPhoneActivity> cactivity;
	CHandler(AsBindPhoneActivity activity) {
		cactivity = new WeakReference<AsBindPhoneActivity>(activity);
	}
	
	@Override
	public void handleMessage(Message msg) {
		// TODO Auto-generated method stub
		super.handleMessage(msg);
		switch (msg.what) {
		case 10011:
			if (btGet != null) {
				btGet.setText("重新获取("+second+")");
			}
			break;
		case 10012:
			if (btGet != null) {
				btGet.setText("获取短信验证码");
			}
			break;
		default:
			DebugUtil.d("msg.what没有匹配的项");
			break;
		}
	}
}


解决方式二 把Handler定义成static,然后用post方法把Runnable对象传送到主线程,这种方式了解一下就可以了

这种方法将要发送的消息转换成了对应的Runable对象,适用于只有一个消息要发送的情形

static class MyHandler extends Handler {  
       
    WeakReference<PopupActivity> mActivity;  
  
    MyHandler(PopupActivity activity) {  
        mActivity =  new  WeakReference<PopupActivity>(activity);  
    }  
  
     @Override   
     public void handleMessage(Message msg) {  
        PopupActivity theActivity = mActivity.get();  
         switch  (msg.what) {  
         //此处可以根据what的值处理多条信息   
         case 0x0001 :  
             //这里可以改变activity中的UI控件的状态   
            theActivity.textView.setText(R.string.hello_world);  
             break ; 
         case 0x0002 :  
             //这里可以改变activity中的UI控件的状态   
            theActivity.textView.setText(R.string.welcome);  
             break ;  
         /*这里可以有多条要处理信息的操作*/   
         /*... ...*/   
    	}  
    }  
};	  
	//实例化一个MyHandler对象   
	MyHandler testHandler =  new  MyHandler( this );  
	  
	private void test1() {  
	     //这里发送了一个空消息,空消息的what值是0x0001   
	    testHandler.sendEmptyMessage( 0x0001 );  
	}  
  
	private void test2() {  
		//这里发送了一个空消息,空消息的what值是0x0001   
		testHandler.sendEmptyMessage( 0x0002 );  
	} 

详细的解释一下

1.Android App启动的时候,Android Framework 为主线程创建一个Looper对象,这个Looper对象将贯穿这个App的整个生命周期,它实现了一个消息队列(Message  Queue),并且开启一个循环来处理Message对象。而Framework的主要事件都包含着内部Message对象,当这些事件被触发的时候,Message对象会被加到消息队列中执行。
2.当一个Handler被实例化时(如上面那样),它将和主线程Looper对象的消息队列相关联,被推到消息队列中的Message对象将持有一个Handler的引用以便于当Looper处理到这个Message的时候,Framework执行Handler的handleMessage(Message)方法。
3.在 Java 语言中,非静态匿名内部类将持有一个对外部类的隐式引用,而静态内部类则不会。

到底内存泄露是在哪里发生的呢?以下面代码为例:

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() { }
    }, 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);
    }
         
    @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, 60 * 10 * 1000);
             
    // Go back to the previous Activity.
    finish();
  }
}
在实际开发中,如果内部类的生命周期和Activity的生命周期不一致(比如上面那种,Activity finish()之后要等10分钟,内部类的实例才会执行),则在Activity中要避免使用非静态的内部类,这种情况,就使用一个静态内部类,同时持有一个对Activity的 WeakReference

参考链接:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1106/1922.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值