[Android 内存泄漏] 了解 Handler leak

基本的原理就是,内部类 ( 包括匿名内部类 ) 不管有无调用,实际上会持有外部类对象的引用。比如下面的代码 C 类可以取得外部类的变量值。

public class InnerTest {
    private String mContent = "hi";

    class B {
        private String mContent = "hi, B";

        class C {
            public void test() {
                System.out.println(InnerTest.this.mContent);
                System.out.println(B.this.mContent);
            }
        }
    }

    public static void main(String[] args) {
        new InnerTest().new B().new C().test();
    }
}


我们来看看会造成 Handler leak 的代码,如下:

public class MemLeakActivity extends Activity {
    ...
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
         ...
        }
    }
}
所以当我们的内部类 IncomingHandler 发出 Message 后, 根据 Android 异步消息処理机制,Message 会持有 Handler 对象引用,而上面的代码,会持有外部类对象,也就是 MemLeakActivity 对象的引用,导致即使在此 Activity 在调用完 onDestroy( )后,只要 Looper 还没有処理完这个 Message( 比如说这个 Message 是设定为延迟十分钟后再処理),MemLeakActivity 的对象便无法被回收,占用了内存实际上却没有作用,便造成了 Handler Leak 内存泄漏。


解决方法:
使用静态(内部)类 + 弱引用( WeakReference )避免 Activity 被 Message 强引用而无法回收。
public class BaseHandler extends Handler {
    WeakReference<Callback> mTarget = null;


    public BaseHandler(Callback cb) {
        mTarget = new WeakReference<>(cb);
    }


    public interface Callback {
        boolean handleMessage(Message msg);
    }


    @Override
    public void handleMessage(Message msg) {
        Callback handler = mTarget.get();


        if (handler != null) {
            handler.handleMessage(msg);
        }
    }
}
使用方式
public class HandlerDemoActivity extends Activity implements BaseHandler.Callback, View.OnClickListener{
    private BaseHandler mHandler;
    private final static int MSG_TEST = 1;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.act_handler_demo);
        mHandler = new BaseHandler(this);
        TextView tv = (TextView) findViewById(R.id.tv);
        tv.setOnClickListener(this);
    }


    @Override
    public boolean handleMessage(Message msg) {
        final int what = msg.what;
        if(what == MSG_TEST) {
            Toast.makeText(this, "TEST", Toast.LENGTH_LONG).show();
        }
        return true;
    }


    @Override
    public void onClick(View v) {
        mHandler.sendEmptyMessage(MSG_TEST);
    }
}
Github 范例

相关参考文章
refs: http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值