我所知道的Handler

简单讲,handler就是两个功能

插入消息,enqueuemessage,msg,when
从消息队列中遍历所有消息,比对msg.when和当前的when,找到合适的位置插入

处理消息,looper.loop会从messagequeue中调用next。取消息,如果消息还没到时间该执行,就会比对时间,下次轮询就通过binder写入,native函数休眠,到时间唤醒执行。

handler内存泄漏

GCRoot 一般是静态变量或者常量可以作为GCROOT
GCROOT 是ThreadLocal,存在于Looper中,Looper被加载就存在,
handler持有activity或者fragment,handler又被message持有,message的target属性,message被messagequeue持有,messagequeue被looper中的threadlocal持有

java中匿名内部类会默认持有外部类的引用

打断持有链

  1. handler.removemesage handler.removecallbacks
  2. handler使用static修饰。

主线程的Looper不允许退出

处理消息,looper取出来后,调用message.tager.dispatchemesage后面调用了handler的handlemessage方法。

还有个callback对象,如果有callback,dispatch会先执行callback的处理,calllback返回true,后面就不处理了,callback返回false就给handler的handlemessage处理了

Meesage对象创建

message创建用的obtain,池化,频繁的创建销毁会导致内存不稳定,抖动,造成卡顿 oom等问题

message pool的最大缓存50

阻塞和休眠,阻塞是被动的,休眠是主动的,阻塞不会让出cpu,休眠会,thread.yield会让出cpu。

子线程主线程通信

handler,livedata,eventbus,flow,rxjava,broadcast,观察者模式不能跨线程

最终都是handler完成的。

Handler监听卡顿

原理是在looper内完成的,looper处理消息的时候,会打印内容,就是Printer,looper可以设置它。

Message消息的分类

同步消息,普通的消息都是同步消息
异步消息,创建handler的时候设置async为true即可
同步屏障,需要通过反射调用,app层无法直接调用,是messagequeue提供的posSyncBarrier方法实现的,返回一个token,时msg的arg1值,用它来取消同步屏障。和普通消息的区别是,msg。target属性为null。

刷新UI的消息是异步消息,发送前先插入了一个同步屏障消息,异步消息处理完成后,要将同步屏障消息移除队列

消息入队

handler消息加入队列,有一系列方法,如下:

// 发送空消息
public final boolean sendEmptyMessage(int what){}
public final boolean sendEmptyMessageDelayed(int what,long delay){}
public final boolean sendEmptyMessageAtTime(int what,long when){}
// 发送消息
public final boolean sendMessage(@NonNull Message msg){}
public final boolean sendMessageDelayed(@NonNull Message msg,long time){}
public final boolean sendMessageAtTime(@NonNull Message msg,long when){}
public final boolean sendMessageAtFrontOfQueue(Message msg) {}
// post发送
public final boolean post(@NonNull Runnable r) {}
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {}
public final boolean postAtTime( 
@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {}
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {}
public final boolean postDelayed(Runnable r, int what, long delayMillis) {}
public final boolean postDelayed( 
 @NonNull Runnable r, @Nullable Object token, long delayMillis) {}
public final boolean postAtFrontOfQueue(@NonNull Runnable r) {}
// enqueue
public final boolean executeOrSendMessage(@NonNull Message msg) {}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, 
 long uptimeMillis) {}

最终都是掉用的enqueueMessage加入队列

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, 
 long uptimeMillis) { 
 msg.target = this; // 绑定消息处理对象
 msg.workSourceUid = ThreadLocalWorkSource.getUid(); 
 
 if (mAsynchronous) { // 根据handler创建是否是异步的,来将消息标记为异步消息 
 msg.setAsynchronous(true); 
 } 
 // 调用messagequeue的方法,加入队列。
 return queue.enqueueMessage(msg, uptimeMillis); 
}

下面看下消息如何入队的

boolean enqueueMessage(Message msg, long when) { 
 if (msg.target == null) { 
 throw new IllegalArgumentException("Message must have a target."); 
 } 
 
 synchronized (this) { 
 if (msg.isInUse()) { 
 throw new IllegalStateException(msg + " This message is already in use."); 
 } 
 
 if (mQuitting) { 
 IllegalStateException e = new IllegalStateException( 
 msg.target + " sending message to a Handler on a dead thread"); 
 Log.w(TAG, e.getMessage(), e); 
 msg.recycle(); 
 return false; 
 } 
 
 msg.markInUse(); 
 msg.when = when; 
 // 当前队列的头
 Message p = mMessages; 
 boolean needWake; 
 if (p == null || when == 0 || when < p.when) { 
 // New head, wake up the event queue if blocked. 
 // 消息队列为null,或者消息是立刻执行的,或者要执行的时间先于头消息的时间,将当前消息作为新的队列的头
 msg.next = p; 
 mMessages = msg; 
 needWake = mBlocked; 
 } else { 
 // Inserted within the middle of the queue. Usually we don't have to wake 
 // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); 
 // 遍历队列,找到合适的位置,将当前消息插入进去
 Message prev; 
 for (;;) { 
 prev = p; 
 p = p.next; 
 if (p == null || when < p.when) { 
 break; 
 } 
 if (needWake && p.isAsynchronous()) { 
 needWake = false; 
 } 
 } 
 msg.next = p; // invariant: p == prev.next 
 prev.next = msg; 
 } 
	// 如果需要的话,唤醒队列,开始处理消息,就是MessageQueue的next方法开始执行
 // We can assume mPtr != 0 because mQuitting is false. 
 if (needWake) { 
 nativeWake(mPtr); 
 } 
 } 
 return true; 
}

取消息以及消息处理

取消息1

取消息入口是Looper的loop方法处理的

public static void loop() { 
 final Looper me = myLooper(); 
 if (me == null) { 
 throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); 
 } 
 if (me.mInLoop) { 
 Slog.w(TAG, "Loop again would have the queued messages be executed" 
 + " before this one completed."); 
 } 
 
 me.mInLoop = true; 
 
 // Make sure the identity of this thread is that of the local process, 
 // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); 
 final long ident = Binder.clearCallingIdentity(); 
 
 // Allow overriding a threshold with a system prop. e.g. 
 // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start' final int thresholdOverride = 
 SystemProperties.getInt("log.looper." 
 + Process.myUid() + "." 
 + Thread.currentThread().getName() 
 + ".slow", 0); 
 
 me.mSlowDeliveryDetected = false; 
	// 无限循环,通过loopOnce取消息
 for (;;) { 
 if (!loopOnce(me, ident, thresholdOverride)) { 
 return; 
 } 
 } 
}

处理消息

private static boolean loopOnce(final Looper me, 
 final long ident, final int thresholdOverride) { 
 // 取消息
 Message msg = me.mQueue.next(); // might block 
 if (msg == null) { 
 // No message indicates that the message queue is quitting. 
 return false; 
 } 
 
 // This must be in a local variable, in case a UI event sets the logger 
 final Printer logging = me.mLogging; 
 if (logging != null) { 
 logging.println(">>>>> Dispatching to " + msg.target + " " 
 + msg.callback + ": " + msg.what); 
 } 
 // Make sure the observer won't change while processing a transaction. 
 final Observer observer = sObserver; 
 
 final long traceTag = me.mTraceTag; 
 long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; 
 long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs; 
 if (thresholdOverride > 0) { 
 slowDispatchThresholdMs = thresholdOverride; 
 slowDeliveryThresholdMs = thresholdOverride; 
 } 
 final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0); 
 final boolean logSlowDispatch = (slowDispatchThresholdMs > 0); 
 
 final boolean needStartTime = logSlowDelivery || logSlowDispatch; 
 final boolean needEndTime = logSlowDispatch; 
 
 if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { 
 Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); 
 } 
 
 final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0; 
 final long dispatchEnd; 
 Object token = null; 
 if (observer != null) { 
 token = observer.messageDispatchStarting(); 
 } 
 long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid); 
 try { 
	 // 这里取出msg的target属性,就是handler对象,进行消息的处理。注意:屏障消息是没有target的。
 msg.target.dispatchMessage(msg); 
 if (observer != null) { 
 observer.messageDispatched(token, msg); 
 } 
 dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; 
 } catch (Exception exception) { 
 if (observer != null) { 
 observer.dispatchingThrewException(token, msg, exception); 
 } 
 throw exception; 
 } finally { 
 ThreadLocalWorkSource.restore(origWorkSource); 
 if (traceTag != 0) { 
 Trace.traceEnd(traceTag); 
 } 
 } 
 if (logSlowDelivery) { 
 if (me.mSlowDeliveryDetected) { 
 if ((dispatchStart - msg.when) <= 10) { 
 Slog.w(TAG, "Drained"); 
 me.mSlowDeliveryDetected = false; 
 } 
 } else { 
 if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", 
 msg)) { 
 // Once we write a slow delivery log, suppress until the queue drains. 
 me.mSlowDeliveryDetected = true; 
 } 
 } 
 } 
 // 这里会打印那些执行慢的消息
 if (logSlowDispatch) { 
 showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg); 
 } 
 
 if (logging != null) { 
 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); 
 } 
 
 // Make sure that during the course of dispatching the 
 // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); 
 if (ident != newIdent) { 
 Log.wtf(TAG, "Thread identity changed from 0x" 
 + Long.toHexString(ident) + " to 0x" 
 + Long.toHexString(newIdent) + " while dispatching to " 
 + msg.target.getClass().getName() + " " 
 + msg.callback + " what=" + msg.what); 
 } 
 
 msg.recycleUnchecked(); 
 
 return true; 
}

取消息2

再看下实际的取消息的方法,MessageQueue的next方法

Message next() { 
 // Return here if the message loop has already quit and been disposed. 
 // This can happen if the application tries to restart a looper after quit // which is not supported. 
 final long ptr = mPtr; 
 if (ptr == 0) { 
 return null; 
 } 
 
 int pendingIdleHandlerCount = -1; // -1 only during first iteration 
 int nextPollTimeoutMillis = 0; 
 for (;;) { 
 if (nextPollTimeoutMillis != 0) { 
 Binder.flushPendingCommands(); 
 } 
	// 这个方法会在没有消息的时候阻塞
 nativePollOnce(ptr, nextPollTimeoutMillis); 
 
 synchronized (this) { 
 // Try to retrieve the next message. Return if found. 
 final long now = SystemClock.uptimeMillis(); 
 Message prevMsg = null;
 // 消息头保存
 Message msg = mMessages; 
 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()); 
 // 循环的作用,找出队列里的异步消息,存储在msg里,或者将同步屏障消息存储在msg中,prevMsg存储的是同步消息 
 } 
 if (msg != null) { 
 if (now < msg.when) { 
	 // 下次的唤醒时间
 // Next message is not ready. Set a timeout to wake up when it is ready. 
 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); 
 } else { 
 // Got a message. 
 mBlocked = false; 
 if (prevMsg != null) { 
 prevMsg.next = msg.next; 
 } else { 
 mMessages = msg.next; 
 } 
 msg.next = null; 
 if (DEBUG) Log.v(TAG, "Returning message: " + msg); 
 msg.markInUse(); 
 // 将取出的消息交给handler处理。 
 return msg; 
 } 
 } else { 
 // No more messages. 
 nextPollTimeoutMillis = -1; 
 } 
 
 // Process the quit message now that all pending messages have been handled. 
 if (mQuitting) { 
 dispose(); 
 return null; 
 } 
 
 // If first time idle, then get the number of idlers to run. 
 // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. 
 if (pendingIdleHandlerCount < 0 
 && (mMessages == null || now < mMessages.when)) { 
 pendingIdleHandlerCount = mIdleHandlers.size(); 
 } 
 if (pendingIdleHandlerCount <= 0) { 
 // No idle handlers to run. Loop and wait some more. 
 mBlocked = true; 
 continue; 
 } 
 
 if (mPendingIdleHandlers == null) { 
 mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; 
 } 
 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); 
 } 
 
 // Run the idle handlers. 
 // We only ever reach this code block during the first iteration. 
 for (int i = 0; i < pendingIdleHandlerCount; i++) { 
 final IdleHandler idler = mPendingIdleHandlers[i]; 
 mPendingIdleHandlers[i] = null; // release the reference to the handler 
 
 boolean keep = false; 
 try { 
 keep = idler.queueIdle(); 
 } catch (Throwable t) { 
 Log.wtf(TAG, "IdleHandler threw exception", t); 
 } 
 
 if (!keep) { 
 synchronized (this) { 
 mIdleHandlers.remove(idler); 
 } 
 } 
 } 
 
 // Reset the idle handler count to 0 so we do not run them again. 
 pendingIdleHandlerCount = 0; 
 
 // While calling an idle handler, a new message could have been delivered 
 // so go back and look again for a pending message without waiting. 
 nextPollTimeoutMillis = 0; 
 } 
}

handler的消息处理

是从dispatchMessage方法开始的,里面进行消息处理

public void dispatchMessage(@NonNull Message msg) {
	// 检查message是否设置了callback对象(runnable类型的)
	if (msg.callback != null) {
	// 执行其run方法
	handleCallback(msg);
	} else {
	// 检查handler是否设置了callback对象
	if (mCallback != null) {
	if (mCallback.handleMessage(msg)) {
	// 如果返回true,后续就不执行了。
	return;
	}
	}
	// 自定义handler的时候,实现该方法处理消息
	handleMessage(msg);
	}
}

IdleHandler是什么?干什么?继续看MessageQueue类。

IdleHandler是MessageQueue的静态内部接口。如下

public static interface IdleHandler { 
 /** 
 * Called when the message queue has run out of messages and will now * wait for more. Return true to keep your idle handler active, false * to have it removed. This may be called if there are still messages * pending in the queue, but they are all scheduled to be dispatched * after the current time. */ 
 
 boolean queueIdle(); 
}

当前线程的消息对立内当前没有消息要处理时,会取出idlehander执行任务,因为执行在主线程,禁止执行耗时操作。返回true表示执行完并不会移除该对象,false执行完一次就移除。
而且,执行时机是不确定的。
执行的地方在next方法内部。

Message next() { 
 // Return here if the message loop has already quit and been disposed. 
 // This can happen if the application tries to restart a looper after quit // which is not supported. 
 final long ptr = mPtr; 
 if (ptr == 0) { 
 return null; 
 } 
 
 int pendingIdleHandlerCount = -1; // -1 only during first iteration 
 int nextPollTimeoutMillis = 0; 
 for (;;) { 
 if (nextPollTimeoutMillis != 0) { 
 Binder.flushPendingCommands(); 
 } 
 
 nativePollOnce(ptr, nextPollTimeoutMillis); 
 
 synchronized (this) { 
 // Try to retrieve the next message. Return if found. 
 final long now = SystemClock.uptimeMillis(); 
 Message prevMsg = null; 
 Message msg = mMessages; 
 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()); 
 } 
 if (msg != null) { 
 if (now < msg.when) { 
 // Next message is not ready. Set a timeout to wake up when it is ready. 
 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); 
 } else { 
 // Got a message. 
 mBlocked = false; 
 if (prevMsg != null) { 
 prevMsg.next = msg.next; 
 } else { 
 mMessages = msg.next; 
 } 
 msg.next = null; 
 if (DEBUG) Log.v(TAG, "Returning message: " + msg); 
 msg.markInUse(); 
 return msg; 
 } 
 } else { 
 // No more messages. 
 nextPollTimeoutMillis = -1; 
 } 
 
 // Process the quit message now that all pending messages have been handled. 
 if (mQuitting) { 
 dispose(); 
 return null; 
 } 
	// 执行到这里,说明没有找到message对象需要执行了,且线程没有退出。
 // If first time idle, then get the number of idlers to run. 
 // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. 
 if (pendingIdleHandlerCount < 0 
 && (mMessages == null || now < mMessages.when)) { 
 pendingIdleHandlerCount = mIdleHandlers.size(); 
 } 
 if (pendingIdleHandlerCount <= 0) { 
 // No idle handlers to run. Loop and wait some more. 
 mBlocked = true; 
 continue; 
 } 
	// 取出idlehandlers
 if (mPendingIdleHandlers == null) { 
 mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; 
 } 
 mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); 
 } 
 
 // Run the idle handlers. 
 // We only ever reach this code block during the first iteration. 
 for (int i = 0; i < pendingIdleHandlerCount; i++) { 
 final IdleHandler idler = mPendingIdleHandlers[i]; 
 mPendingIdleHandlers[i] = null; // release the reference to the handler 
 
 boolean keep = false; 
 try { 
	 // 执行idlehandler的方法
 keep = idler.queueIdle(); 
 } catch (Throwable t) { 
 Log.wtf(TAG, "IdleHandler threw exception", t); 
 } 
 
 if (!keep) { 
	 // 需要移除的话,在此处进行移除
 synchronized (this) { 
 mIdleHandlers.remove(idler); 
 } 
 } 
 } 
 
 // Reset the idle handler count to 0 so we do not run them again. 
 pendingIdleHandlerCount = 0; 
 
 // While calling an idle handler, a new message could have been delivered 
 // so go back and look again for a pending message without waiting. 
 nextPollTimeoutMillis = 0; 
 } 
}
作者:真菜啊原文地址:https://www.cnblogs.com/android-lol/p/17410693.html

%s 个评论

要回复文章请先登录注册