android 消息系统Handler、MessageQueue、Looper源码学习
来源:互联网 发布:python安装包官网下载 编辑:程序博客网 时间:2024/05/22 12:37
android消息系统
整体框架如图所示
在安卓的消息系统中,每个线程有一个Looper,Looper中有一个MessageQueue,Handler向这个队列中投递Message,Looper循环拿出Message再交由Handler处理。整体是一个生产者消费者模式,这四部分也就构成了android的消息系统。
先来看一个最简单的例子
//这段代码在某个Activity的onCreate中 Handler handler = new Handler(Looper.getMainLooper()); Message msg = Message.obtain(handler, new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext,"I am a message",Toast.LENGTH_SHORT).show(); } }); handler.sendMessage(msg);
效果就是,在当前窗口弹出I am a message,当然就其实现的效果而言完全多此一举。但是就分析android消息系统,却是很简单有效的例子。
源码分析
Message
Message中封装了我们常用的what、arg1、arg2、obj等参数,除此之外还有target:一个Handler类型,由前文可知一个Message最终还是交给一个Handler执行的,这个target存放的就是消息的目的地、callback,一个消息的回调,我们通过handler.post(new Runnable{…})发送的消息,这个Runnable即被存为callback。
首先来看消息的获取:
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); } public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; }
对照最开始的例子,Message.obtain(Handler h, Runnable callback)首先调用obtain获取了一个新的Message对象,然后为其设置了目的地Handler和回调函数callback,Message类中有很多不同的obtain函数,实际上只是为我们封装了一些赋值的操作。
再看Message.obtain()方法,sPoolSync是一个给静态方法用的静态锁,sPool是一个静态的Message变量,在消息的获取这里,android使用了享元模式,对于会被重复使用的Message消息,没有对每一次请求都新建一个对象,而是通过维护一个Message链表,在有空闲消息的时候从链表中拿Message,没有时才新建Message。
可以看到obtain中只有从链表中去Message和新建Message,而没有向链表中存储的过程。存储这部分就要看Message.recycle()了:
public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
回收过程,首先把原链表的头指向当前被回收消息的下一个节点,然后再把链表头指针知道当前节点即可。整个操作也就是将Message添加到链表的首位。
MessageQueue 消息队列
MessageQueue是在Looper中的,这点从Looper的构造函数可以看出来:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
对于每个MessageQueue,是链表实现的消息队列。首先是入队操作:
boolean enqueueMessage(Message msg, long when) { if (msg.isInUse()) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null) { throw new AndroidRuntimeException("Message must have a target."); } synchronized (this) { if (mQuitting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; } msg.when = when; //mMessages是链表的头指针 Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { // 将消息插入到队列的首位 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) { nativeWake(mPtr); } } return true; }
next操作,包含取出和删除一条消息。
Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } //从native层消息队列取出消息 nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // 找到非异步的Message或者消息队列尾部的Message取出 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 { // 获取一个Message mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); msg.markInUse(); return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } // 检查退出标志位 if (mQuitting) { dispose(); return null; } ... } }
Handler
Handler的作用是放入消息和处理消息,承担了生产者的工作和部分消费者的工作。
首先通过Handler发送一条消息:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }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); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
通过一层一层嵌套,真正的逻辑在sendMessageAtTime,可以看到仅仅是执行了一下入队操作。作为生产者的工作也就执行完成,消费者部分后面要结合Looper分析。
除了sendMessage方法,常用的handler.post方法也是封装为Message,主要过程和上面相似。
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
Looper
Looper类中,Looper的实例获取是通过ThreadLocal的,ThreadLocal会为每一个线程提供一个副本,通过set和get方法每个线程获取作用域仅属于该线程的变量值。对于UI线程而言,会执行Looper.prepareMainLooper()来完成Looper的初始化:
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }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)); }
Looper.prepare()方法将当前线程的ThreadLocal设置了一个新的Looper对象,prepareMainLooper则是把当前线程的Looper对象赋值给类变量sMainLooper ,该方法在ActivityThread中调用,设置了一个全局的给UI线程使用的Looper。
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."); } final MessageQueue queue = me.mQueue; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); //从Looper中获取MessageQueue,循环取出消息 for (;;) { Message msg = queue.next(); ... //将消息发送给目标处理。 msg.target.dispatchMessage(msg); ... //回收消息,把消息放在消息池中 msg.recycle(); } }
主要逻辑很清晰,前面分析过msg.target是一个Handler,表示处理消息的目标,通过命令模式将消息交给对应Handler处理。下面是Handler中处理消息的方法:
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }private static void handleCallback(Message message) { message.callback.run(); }public void handleMessage(Message msg) { }
如果我们是通过handler.post的方法发送一条消息,那么直接执行callback中的逻辑。否则通过实现Callback接口回调,或者执行handleMessage,handleMessage也就是我们子类覆写的方法。可以看到,虽然逻辑部分是我们在Handler中实现的,但是调用的地方却是Looper的线程。因为一个Looper绑定一个线程,我们也可以通过比较Looper来比较线程。
总结
通过分析源码,可以知道android中可以通过Looper为每一个线程创建一个消息队里,UI线程的Looper在Activity启动前就已经初始化。那么对于我们自定义的线程,很明显也可以绑定Looper。
自定义线程绑定Looper,最明显的好处就是可以实现线程间通信了,同时由于借助了消息队列,也将并行转为串行实现了线程安全。看一个简单的例子:
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); handlerA = new Handler(Looper.myLooper()){ @Override public void handleMessage(Message msg) { Log.d("TAG", msg.obj.toString()); } }; Looper.loop(); } }).start();
上述在线程中创建绑定了一个Looper,然后新建一个和当前Looper绑定的Handler,这样可以通过该Handler向Looper的MessageQueue中添加消息,然后由Looper.loop取出消息并执行。
Message msg = new Message(); msg.obj = "i am main thread"; handlerA.sendMessage(msg);
在主线程或者其它线程中获取handler然后发送消息,最终可以看到消息被线程接收并处理。这里msg的target也就是handlerA。注意如果线程工作结束,需要调用Looper.quit(),不然会因为Looper一直循环而导致线程无法结束。
最后经过上面的分析,流程图可以画的更为细致:
- android 消息系统Handler、MessageQueue、Looper源码学习
- Android消息传递源码理解。Handler,Looper,MessageQueue,Message
- Android 消息机制 - Handler, Looper, Message, MessageQueue 的源码分析
- Android消息机制Handler,MessageQueue,Looper源码解析
- Android消息机制(Handler,Looper,MessageQueue)-源码分析
- Android 源码(6) --- 异步消息机制Handler、Looper、MessageQueue
- Android消息队列源码解析(Handler、Looper、Message、MessageQueue)
- android消息处理机制学习(三)-Handler,Message,MessageQueue,Looper源码分析
- android异步消息处理机制 handler MessageQueue Looper 类 学习
- Android的消息机制学习(一)Looper,Handler,MessageQueue
- Android异步消息处理 Handler Looper MessageQueue
- Android消息处理框架:Looper,Handler,MessageQueue ...
- android Handler Looper,MessageQueue消息机制原理
- Android消息机制 Handler,Looper,MessageQueue
- Android消息机制:Looper、Handler、MessageQueue分析
- Android 消息机制---Handler,Looper,MessageQueue,ThreadLocal
- Android消息机制 — Handler-Looper-MessageQueue
- Android消息传递机制---Handler,MessageQueue,Looper.
- UFLDL深度学习教程翻译之自我学习
- Ubuntu 14.04 安装IRAF, PyRAF
- Java初级应用----打印回字型
- android之数据存储3
- C\C++代码优化的27个建议
- android 消息系统Handler、MessageQueue、Looper源码学习
- ListView + CheckBox (全选,反选,取消)
- 初学C#:贪吃蛇
- Q45:圆圈中最后剩下的数字
- 序列化和反序列化
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
- DSP+Linux开发技术分析
- 详解SESSION与COOKIE的区别
- 有道内推笔试