Handler是什么
Handler是Android 基于事件驱动的线程之间消息传递处理机制。
独立分配虚拟机的好处
好处在于当自身app发生崩溃时不会影响到手机上的其他app,做好了风险隔离。
Handler中的几个主要类
1.Looper:传递消息入队出队的主要处理者
2.MessageQueue:
一个优先级的消息队列,队列内的消息按照执行时间先后排列
2.Message:队列消息 主要注意 获取Message的复用方式
Handler的整体工作流程
handler机制就是一个传送带的运转机制。
1)MessageQueue就像履带。
2)Thread就像背后的动力,就是我们通信都是基于线程而来的。
3)传送带的滚动需要一个开关给电机通电,那么就相当于我们的loop函数,而这个loop里面的for循环就会带着不断
的滚动,去轮询messageQueue
4)Message就是 我们的货物了。
-
出队(取出消息)
从 ActivityThread ->main开始看这里启动了整个进程的消息监分发处理
{
...
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//启动loop 开始循环消息
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
接着进入到了Looper的loop方法里,从 Message msg = queue.next(); 中取出消息
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// 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);
boolean slowDeliveryDetected = false;
for (;;) {
//取出消息开始处理
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
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();
}
}
从queue.next() 中 msg取出后会计算是否到了执行时间如果没到nativePollOnce继续阻塞等待 ,直到有人调用nativeWakeUp唤醒它。
一般阻塞有2种情况
- 消息未到执行时间 系统调用 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);重新计算等待时间
- 消息队列为空 nextPollTimeoutMillis = -1
在next()里要退出的loop循环只有一种方式 那就是调用quit的函数将mQuitting置为true
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);->epoll_wait()
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;
}
//只有quit才会停下loop
// 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;
}
}
//退出loop的办法
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
//唤醒
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
-
入队(发送消息)
通常我们使用handler发送消息 都是通过sendMessage 那么就以他为切入点:
sendMessage——>sendMessageDelayed——>sendMessageAtTime
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:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
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.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
//通知nativePollOnce
nativeWake(mPtr);
}
}
return true;
}
入队的流程总体比较简单 主要就是 添加消息到队列,如果当前需要唤醒 发送唤醒
-
MessageQueue中的 阻塞方式:
通过调用nativePollOnce 调用到jni的层 再到c++层最终调到epoll_wait 函数等待
nativeWakeUp
Handler 中的消息同步屏障
当消息队列开启同步屏障的时候(即标识为 msg.target == null ),消息机制在处理消息的时候,优先处理异步消息。这样,同步屏障就起到了一种过滤和优先级的作用。
找到isAsynchronous()为true的异步消息 优先处理
一般系统内比较常用到
Android 系统中
的 UI 更新相关的消息即为异步消息,需要优先处理。
比如,在 View 更新时,draw、requestLayout、invalidate 等很多地方都调用了
注意next方法中
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());
}
开启同步屏障:
Handler.getLooper().getQueue().postSyncBarrier()
移除同步屏障:
Handler.getLooper().getQueue().removeSyncBarrier();
Message应该怎么用:
一般要创建一个message对象有两种方法 一种是直接new 直接在内存开辟空间 另一种是obtain即 优先使用空的message 如果没有再去new
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
HandlerThread
相较于传统的Thread HandlerThread 将looper的准备工作再内部先处理好了
Handler常见QA
1.Q: 一个线程有几个 Handler?
A:看你new几个
2.Q:一个线程有几个 Looper?如何保证?
A:1个 通过threadLocal 来保证 当获取looper时 会先从threadLocal中获取 如果存在即返回,而当你想再次设置新的looper如果旧的已经存在 会抛出异常
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
3.Q:Handler内存泄漏原因? 为什么其他的内部类没有说过有这个问题?
A:handler持有了外部类的引用 而 message 持有了handler 导致该释放的对象无法释放造成内存泄漏 其他类如adapter因为与外部类生命周期一致 不会存在内存泄漏 随activity的消亡而消亡
4.Q:为何主线程可以new Handler?如果想要在子线程中new Handler 要做些什么准备?
A:因为主线程的looper从activitythread的main方法就准备好了 而 子线程如果要使用looper应该调用prepare()和loop()方法
5.Q:子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?
A:调用quit() 是mQuitting置为true 同时nativeWakeup 唤醒 退出loop循环
6.Q:既然可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时各个 Handler 可能处于不同线程),那它内部是如何确保线程安全的?取消息呢?
A: 通过 synchronized关键字 加锁来确保 无法同时调用入队出队
7.Q:我们使用 Message 时应该如何创建它?
调用 obtain 复用message(享元设计模式)
8.Looper死循环为什么不会导致应用卡死
looper在没消息/未到消息时间处理时 会进入nativePollOnce使自己进入阻塞状态 让出cpu 执行权 供其他线程使用,等到 有消息入队又会唤醒它