在避免内存泄露的文章中,Handler经常被提起,原因就是对象的强引用,比如一个Activity内部有一个Handler对象在运行
private Handler handler;
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
}
};
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
当我们使用上面代码创建一个Handler时,IDE就会给我提示
This Handler class should be static or leaks might occur (com.example.androidtest.MainActivity.2)
告诉我们,会产生内存泄露。
当Activity关闭时,Handler不一定处理完毕,但是Handler对Activity有引用关系,导致GC无法回收Activity对象,造成内存泄露。那么Handler为什么会这样呢,那就看看它的实现吧。
在Handler对象中会隐式的引用到Activity,这就形成了强引用,也是造成内存泄露的原因。 public static void prepareMainLooper() {
//调用prepare创建Looper
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//这里new了一个Looper对象
sThreadLocal.set(new Looper(quitAllowed));
}
//sThreadLocal是个静态变量
static final ThreadLocal sThreadLocal = new ThreadLocal();
final MessageQueue mQueue;
handler.sendMessage发送消息最终调用下面的方法,持有了Activity
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//这里就是,消息持有了handler对象,handler持有Activity
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class extends Handler> klass = getClass();
//看看这里,如果是匿名类或者成员类或者局部类,并且不是静态对象,系统就会提示警告,有内存泄露的危险
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//取出Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}