常见有内存泄漏的写法
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
解决方案
private final MyHandler handler = new MyHandler(this);
private static class MyHandler extends Handler {
private final WeakReference<Activity> weakAcitivity;
public MyHandler(Activity activity) {
weakAcitivity = new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = weakAcitivity.get();
if (null != activity) {
// coding
}
}
}
为什么会出现内存泄漏
注:以下均以在主线程new Handler()举例,在其他线程初始化Handler情况类似
跨进程原理概述
Handler跨线程原理是主线程中持有一个MessageQueue,在新线程中对这个队列进行插入(sendMessage()),然后在主线程循环读取然后通过调用callback,再调用handleMessage()实现跨线程的。
内存泄漏原理概述
因为很有可能会有好几个Handler同时向主线程MessageQueue 插入数据,而callback的时候需要回调到各自的Handler中去,所以插入MessageQueue中的实例Message会持有当前handler实例。而MessageQueue的生命周期是和当前主线程的生命周期一致的,如果Acitivity持有handler的话,那就必然会造成内存泄漏了。
源码分析
-
所有的
sendMessage()最终都会调用下面代码public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); } -
而在
enqueueMessage()中,它会把this,也就是当前handler保存在msg中,然后插入到当前主线程的MessageQueue中。到此为止,真相大白。private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); } -
回调
callback,在Looper.java中不断循环MessageQueue从中取出Message(只显示了部分关键代码)public static void loop() { for (;;) { try { msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } } } -
回到
Handler中,看看被Looper调用的dispatchMessage()方法:public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } 至此,真相得到了验证。
