[Android 内存泄漏] 了解 Handler leak

来源:互联网 发布:淘宝如何使用电子面单 编辑:程序博客网 时间:2024/06/07 02:17

基本的原理就是,内部类 ( 包括匿名内部类 ) 不管有无调用,实际上会持有外部类对象的引用。比如下面的代码 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

0 0
原创粉丝点击