常见有内存泄漏的写法
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); } }
-
至此,真相得到了验证。
网友评论