1.直接在activity中new Handler问题泄漏的原因修正
因为最后所有线程的looper,都会随着对应的线程存入到ThreadLocal中。但是要注意的一点是,在ThreadLocal中,key是弱引用,同时这个value也是可以以一种正确方式进行回收的。因此这可以避免内存泄漏问题的产生。那么真正的原因是什么呢?
private static Looper sMainLooper;
可以发现主线程对应的looper是static的,因此在主线程中直接new一个handler。会有一个GCRoot,导致内存泄漏。
2.handler中的四类消息类型
2.1 普通的message
这个message就是普通发送的message,target属性不为空,知道谁要处理这个message
2.2 异步message
这类message的优先级较高message的如下方法表明优先级较高
public boolean isAsynchronous() {
return (flags & FLAG_ASYNCHRONOUS) != 0;
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
这个异步消息通常用来刷新UI,因此优先级很高
2.3 屏障消息
这类消息是伴随着异步消息的发出而发出的。一个异步消息必然会对应一个屏障消息。这个屏障message的特征是target属性为null。
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
上面的这个是next的部分源码,上面的源码表示,当一个发现队头的消息是屏障消息的时候,就会不断查找“相邻”的一异步消息然后进行处理。当执行完异步消息以后,系统会发出一个消除屏障消息的函数请求,移除这个屏障消息.看如下源码
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
根据token删除屏障消息。
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
上面的代码表示发送异步消息之前一定会发送一个屏障消息,并且异步消息一定在屏障消息后面
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
插入屏障消息的时候一定会返回这个屏障消息的token数值