android消息处理源码分析
程序员文章站
2022-03-14 14:26:20
一、简介消息处理机制主要涉及到这几个类:1.Looper2.MessageQueue3.Message4.Handler 二、源码分析 Looper.class的关键源码: 消息循环退出过程 从上面可以看到loop()方法是一个死循环,只有当MessageQueue的next()方法返回null时才 ......
一、简介
消息处理机制主要涉及到这几个类:
1.looper
2.messagequeue
3.message
4.handler
二、源码分析
looper.class的关键源码:
//保存looper对象,在android中每创建一个消息队列,就有一个并且是唯一一个与之对应的looper对象 static final threadlocal<looper> sthreadlocal = new threadlocal<looper>(); //主线程的looper private static looper smainlooper; //消息队列 final messagequeue mqueue; final thread mthread; //子线程中通过调用该方法来创建消息队列 public static void prepare() { prepare(true); } 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 void preparemainlooper() { prepare(false); synchronized (looper.class) { if (smainlooper != null) { throw new illegalstateexception("the main looper has already been prepared."); } smainlooper = mylooper(); } } //实例化looper,创建消息队列,获取当前线程 private looper(boolean quitallowed) { mqueue = new messagequeue(quitallowed); mthread = thread.currentthread(); } //调用loop方法开启消息循环 public static void loop() { //获取当前的looper对象,若为null,抛出异常 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; for (;;) { //调用next()方法从消息队列中获取消息,如果为null,结束循环;否则,继续执行(有可能会阻塞) message msg = queue.next(); if (msg == null) { return; } ...... try { //调用handler的dispatchmessage(msg)分发消息 msg.target.dispatchmessage(msg); } finally { ...... } //回收消息资源 msg.recycleunchecked(); } } //消息循环退出 public void quit() { mqueue.quit(false); } public void quitsafely() { mqueue.quit(true); }
消息循环退出过程
从上面可以看到loop()方法是一个死循环,只有当messagequeue的next()方法返回null时才会结束循环。那么messagequeue的next()方法何时为null呢?
在looper类中我们看到了两个结束的方法quit()和quitsalely()。
两者的区别就是quit()方法直接结束循环,处理掉messagequeue中所有的消息。
quitsafely()在处理完消息队列中的剩余的非延时消息(延时消息(延迟发送的消息)直接回收)时才退出。这两个方法都调用了messagequeue的quit()方法
messagequeue.class 的关键源码:
messagequeue中最重要的就是两个方法:
1.enqueuemessage()向队列中插入消息
2.next() 从队列中取出消息
/* *messagequeue中enqueuemessage方法的目的有两个: *1.插入消息到消息队列 *2.唤醒looper中等待的线程(如果是即时消息并且线程是阻塞状态) */ boolean enqueuemessage(message msg, long when) { //发送该消息的handler为null,抛出异常 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"); msg.recycle(); return false; } msg.markinuse(); msg.when = when; //消息队列的第一个元素,messagequeue中的成员变量mmessages指向的就是该链表的头部元素。 message p = mmessages; boolean needwake; if (p == null || when == 0 || when < p.when) { //如果此队列中头部元素是null(空的队列,一般是第一次),或者此消息不是延时的消息,则此消息需要被立即处理, //将该消息作为新的头部,并将此消息的next指向旧的头部。如果是阻塞状态则需要唤醒。 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; prev.next = msg; } if (needwake) { nativewake(mptr); } } return true; } message next() { //与native方法相关,当mptr为0时返回null,退出消息循环 final long ptr = mptr; if (ptr == 0) { return null; } int pendingidlehandlercount = -1; //0不进入睡眠,-1进入睡眠 int nextpolltimeoutmillis = 0; for (;;) { if (nextpolltimeoutmillis != 0) { //处理当前线程中待处理的binder进程间通信请求 binder.flushpendingcommands(); } //native方法,nextpolltimeoutmillis为-1时进入睡眠状态 //阻塞方法,主要是通过native层的epoll监听文件描述符的写入事件来实现的。 //如果nextpolltimeoutmillis=-1,一直阻塞不会超时。 //如果nextpolltimeoutmillis=0,不会阻塞,立即返回。 //如果nextpolltimeoutmillis>0,最长阻塞nextpolltimeoutmillis毫秒(超时),如果期间有程序唤醒会立即返回 nativepollonce(ptr, nextpolltimeoutmillis); synchronized (this) { final long now = systemclock.uptimemillis(); message prevmsg = null; message msg = mmessages; if (msg != null && msg.target == null) { 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 { //正常取出消息,设置mblocked = false代表目前没有阻塞 mblocked = false; if (prevmsg != null) { prevmsg.next = msg.next; } else { mmessages = msg.next; } msg.next = null; 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; } // 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); } } //非睡眠状态下处理idlehandler接口 for (int i = 0; i < pendingidlehandlercount; i++) { final idlehandler idler = mpendingidlehandlers[i]; // release the reference to the handler mpendingidlehandlers[i] = null; boolean keep = false; try { keep = idler.queueidle(); } catch (throwable t) { log.wtf(tag, "idlehandler threw exception", t); } if (!keep) { synchronized (this) { midlehandlers.remove(idler); } } } pendingidlehandlercount = 0; nextpolltimeoutmillis = 0; } }
handler.class源码分析:
/* *通过handler类向线程的消息队列发送消息, *每个handler对象中都有一个looper对象和messagequeue对象 */ 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) {...} //获取消息队列 mqueue = mlooper.mqueue; mcallback = callback; masynchronous = async; } /* *多种sendmessage方法,最终都调用了同一个方法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); } /* *1.当message中的callback不为null时,执行message中的callback中的方法。这个callback时一个runnable接口。 *2.当handler中的callback接口不为null时,执行callback接口中的方法。 *3.直接执行handler中的handlemessage()方法。 */ public void dispatchmessage(message msg) { // 消息callback接口不为null,执行callback接口 if (msg.callback != null) { handlecallback(msg); } else { if (mcallback != null) { //handler callback接口不为null,执行接口方法 if (mcallback.handlemessage(msg)) { return; } } //处理消息 handlemessage(msg); } }
上一篇: SqlServer 触发器 详细讲解
下一篇: MySQL语句整理(二)