Handler源码
Posted cao_null
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handler源码相关的知识,希望对你有一定的参考价值。
Handler
public Handler()
this(null, false);
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 " + Thread.currentThread()
+ " that has not called Looper.prepare()");
//获取MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
//异步先按住不表
mAsynchronous = async;
Looper
Looper如此关键,没有就crash,看下Looper生成的过程
public static @Nullable Looper myLooper()
return sThreadLocal.get();//ThreadLocal保证每个线程都有独立的Looper
//创建过程默认能退出
public static void prepare()
prepare(true);
private static void prepare(boolean quitAllowed)
//一个线程只有一个Looper
if (sThreadLocal.get() != null)
throw new RuntimeException("Only one Looper may be created per thread");
sThreadLocal.set(new Looper(quitAllowed));
private Looper(boolean quitAllowed)
//创建MessageQueue
mQueue = new MessageQueue(quitAllowed);
//获取当前线程
mThread = Thread.currentThread();
单独分析主线程也就是UI线程创建Looper过程
//主线程创建sMainLooper
public static void prepareMainLooper()
prepare(false);
synchronized (Looper.class)
if (sMainLooper != null)
throw new IllegalStateException("The main Looper has already been prepared.");
sMainLooper = myLooper();
//ActivityThread
public static void main(String[] args)
...
//创建主线程Looper
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);
//启动looper
Looper.loop();
//无限循环走到这说明出异常了
throw new RuntimeException("Main thread loop unexpectedly exited");
/**
* Run the message queue in this thread. Be sure to call
* @link #quit() to end the loop.
*/
//官方注释要求确保要调用
public static void loop()
final Looper me = myLooper();
if (me == null) //必须先prepare
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)
//没消息说明正在推出
return;
// 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);
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;
try
//分发
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
finally
if (traceTag != 0) //trace相关
Trace.traceEnd(traceTag);
if (logSlowDelivery)
if (slowDeliveryDetected)
if ((dispatchStart - msg.when) <= 10)
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
else
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg))
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = 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);
//回收message
msg.recycleUnchecked();
MessageQueue和Message
public final class Message implements Parcelable //继承自Parcelable
public int what;
public Object obj;
//下面的是访问权限是包内
/*package*/ int flags;
/*package*/ long when;
/*package*/ Bundle data;
/*package*/ Handler target;
/*package*/ Runnable callback;
// sometimes we store linked lists of these things
/*package*/ Message next;
/** @hide */
//下面是static修饰的
public static final Object sPoolSync = new Object();//同步锁
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;//数据池最大size
public Message()
//生成Message的时候最终都是调用obtain
public static Message obtain()
synchronized (sPoolSync)
if (sPool != null)
Message m = sPool;
sPool = m.next;//返回当前sPool,然后挪动next指针
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
return new Message();//如果超过了就重新new
//这是回收
public void recycle()
if (isInUse())
if (gCheckRecycle)
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
return;
recycleUnchecked();
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
void recycleUnchecked()
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync)
if (sPoolSize < MAX_POOL_SIZE) //小于最大容量
next = sPool;//挪动指针
sPool = this;
sPoolSize++;
这里我们知道了message的数据结构是通过next串联起来的,并且最好使用obtain而避免自己new,可以提高性能。
然后是MessageQueue
public final class MessageQueue
//能否退出
private final boolean mQuitAllowed;
@SuppressWarnings("unused")
private long mPtr; //native用的
Message mMessages;
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;
// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private int mNextBarrierToken;
//下面这些都是native方法,暂时不深究
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr);
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
MessageQueue(boolean quitAllowed)
//主线程不允许退出,子线程允许
mQuitAllowed = quitAllowed;
//记录消息队列
mPtr = nativeInit();
next方法信息量比较大
Message next()
final long ptr = mPtr;
if (ptr == 0) // message的loop已经退出而且执行了disposed.
return null;
int pendingIdleHandlerCount = -1; // 只有第一次是-1
int nextPollTimeoutMillis = 0;
for (;;) //又是一个死循环
if (nextPollTimeoutMillis != 0)
Binder.flushPendingCommands();
//阻塞方法,会被wake唤醒,也可以在nextPollTimeoutMillis时间后唤醒
//nextPollTimeoutMillis是0立即返回,-1就阻塞,否则等到nextPollTimeoutMillis时间后返回
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)
//这里target是null,说明遇到了barrier
do
prevMsg = msg;//如果执行了这里
msg = msg.next;
while (msg != null && !msg.isAsynchronous());//找到下一个异步消息为止
if (msg != null)
if (now < msg.when)
// 下个消息时间还没到,设置等待时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
else
// Got a message.
mBlocked = false;
if (prevMsg != null) //看上面执行了prevMsg赋值,说明找到了异步消息,则重新链接message表
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.没信息重置为1
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();
//如果依然是-1说明不能执行IdleHandler,所以block,跳出循环,如果nextPollTimeoutMillis也是-1则回到之前的nativepullonce
if (pendingIdleHandlerCount <= 0)
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
//初始化最少4个handlers
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();//执行具体的queueIdle
catch (Throwable t)
Log.wtf(TAG, "IdleHandler threw exception", t);
if (!keep) //如果返回true则remove,否则无限循环
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.
//有可能有普通消息过来,直接设置0,不等待进入下次循环
nextPollTimeoutMillis = 0;
看完了next出列,接下来看enqueueMessage入列。
boolean enqueueMessage(Message msg, long when)
//两个必要的检查,为什么必须有target?刚才next还有没有target的情况,晚点再返回来看
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) //之前没有消息或者已经到了触发时间
//新入列的插入头部
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.
//是否唤醒需要看target异步消息
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)
nativeWake(mPtr);//唤醒
return true;
接下来看一下同步屏障是什么
public int postSyncBarrier()
return postSyncBarrier(SystemClock.uptimeMillis());//同步屏障是隐藏方法,且只支持当前时间
private int postSyncBarrier(long when) //这里的message没有target
// 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;
然后是移除同步屏障
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);
小结:
next的时候,假设有同步屏障,接下来只取异步消息,同步消息全部等待,来保证异步消息尽快执行。查看调用,使用同步屏障的地方主要在编舞者等系统关键时刻。消息的入队和出队在这基本分析完了,接下来是事件分发。
消息分发
Looper中调用了msg.target.dispatchMessage,具体看下
public void dispatchMessage(Message msg)
if (msg.callback != null) //先判断msg是否有callback,有就执行handleCallback
handleCallback(msg);
else
if (mCallback != null) //否则调用handler的callback
if (mCallback.handleMessage(msg))
return;
handleMessage(msg);//没人处理走这
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg)
还有时间发送的post
public final boolean post(Runnable r)
return sendMessageDelayed(getPostMessage(r), 0);
public final boolean postAtTime(Runnable r, long uptimeMillis)
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
//最终都执行这个,传入两个必备的参数,Message和时间
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);
总结
分工
Message:消息本身,存储一些target,data之类的数据
MessageQueue:消息队列主要维护消息,取出next或者插入数据enqueueMessage,也维护同步屏障异步消息等逻辑。
Looper:维持线程和Looper循环对应关系,分发到对应的msg。
Handler:负责发送和处理最终事件逻辑。
系统UI相关
同步屏障:加入同步屏障后,同步消息全部阻塞,异步消息能正常执行。
异步消息:可以理解为紧急消息,避免因为同步消息过多导致执行不及时。
使用在编舞者等系统UI关键操作中,避免消息过多导致系统关键操作卡顿。
本地方法
nativePollOnce:维持主线程不退出,并且阻塞逻辑,不占用CPU资源
nativeWake:适当时机唤醒循环
更多native方法逻辑,后续整理再发
以上是关于Handler源码的主要内容,如果未能解决你的问题,请参考以下文章