下圖為Android消息處理機(jī)制順序圖: 由圖可知,,第一步通過調(diào)用Looper.prepare()來創(chuàng)建Looper和MessageQueue java對(duì)象,MessageQueue java類通過保存單向鏈表頭mMessages來遍歷所有消息,,注意此單向鏈表按時(shí)間順序從早到晚排列,,因此mMessages指向的消息總是為需最早處理的消息。在第5步創(chuàng)建C++ Looper對(duì)象,,在其中創(chuàng)建讀寫管道并通過epoll來監(jiān)控讀管道,。 第7步創(chuàng)建Handler給用戶使用,第8步在消息處理線程內(nèi)調(diào)用Looper.loop()來進(jìn)入消息處理循環(huán),,在10步取下一消息時(shí)調(diào)用nativePollOnce方法,,直到13步調(diào)到Looper.pollOnce(),在這里將等待管道POLLIN事件一定時(shí)間(timeoutMillis毫秒),,如果有事件則返回否則等待timeoutMillis毫秒。在第10步MessageQueue.next()取下一消息時(shí),,將無限循環(huán)直到得到消息,。循環(huán)時(shí)第一次傳的超時(shí)時(shí)間timeoutMillis=0,如果此時(shí)尚無消息,,則檢查是否有IdleHandler,如有則調(diào)用所有Handler并置Handler為空,,timeoutMillis設(shè)為0進(jìn)行第二次查詢, 以后timeoutMillis將設(shè)為-1,,因此線程將一直掛起,,直到有消息到來,。
public class MessageQueue{ final Message next() { int pendingIdleHandlerCount = -1; // -1 only during first iteration int nextPollTimeoutMillis = 0; //第一次立刻返回不等待 for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(mPtr, nextPollTimeoutMillis); //第一次=0 synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); final Message msg = mMessages; if (msg != null) { final long when = msg.when; if (now >= when) { //如果消息發(fā)送時(shí)間滿足 mBlocked = false; mMessages = msg.next; msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); msg.markInUse(); return msg; //取消息成功 } else { nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE); //如果有消息但消息尚未到達(dá)發(fā)送時(shí)間,則以該時(shí)間到當(dāng)前時(shí)間的時(shí)間差作為下次查詢超時(shí)的時(shí)間 } } else { nextPollTimeoutMillis = -1; //無限等待 } // If first time, then get the number of idlers to run. if (pendingIdleHandlerCount < 0) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount == 0) { //如果尚未設(shè)置IdleHandler // 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("MessageQueue", "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; } } 第17步用戶線程通過Handler發(fā)送消息,,在20步將調(diào)用nativeWake來喚醒消息處理線程,。最終第24步消息被處理。
final boolean enqueueMessage(Message msg, long when) { if (msg.isInUse()) { throw new AndroidRuntimeException(msg + " This message is already in use."); } if (msg.target == null && !mQuitAllowed) { throw new RuntimeException("Main thread not allowed to quit"); } final boolean needWake; synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread"); return false; } else if (msg.target == null) { mQuiting = true; } msg.when = when; Message p = mMessages; if (p == null || when == 0 || when < p.when) { //如果消息隊(duì)列為空或者當(dāng)前消息為發(fā)送時(shí)間最早的消息 msg.next = p; mMessages = msg; needWake = mBlocked; // mBlocked=true表示線程已被掛起 } else { Message prev = null; while (p != null && p.when <= when) { prev = p; p = p.next; } msg.next = prev.next; prev.next = msg; needWake = false; // still waiting on head, no need to wake up } } if (needWake) { nativeWake(mPtr); //喚醒線程 } return true; } MessageQueue java類單向鏈表:
public final class Message implements Parcelable { Message next; //消息鏈表頭 典型的消息處理代碼
* class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); //創(chuàng)建Looper對(duì)象,在Looper對(duì)象創(chuàng)建時(shí)將創(chuàng)建MessageQueue.最后將Looper對(duì)象存儲(chǔ)在線程局部變量中 * * mHandler = new Handler() { //創(chuàng)建Handler對(duì)象,,在此將讀取線程局部變量得到本線程的Looper對(duì)象及消息隊(duì)列 * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); //進(jìn)入Looper對(duì)象的消息處理循環(huán) * } * } 用戶主要操作接口類Handler,可以通過重載handleMessage()方法實(shí)現(xiàn)自定義方法處理: Handler.java
public void dispatchMessage(Message msg) { if (msg.callback != null) { //如果消息已設(shè)置callback,則調(diào)用該callback函數(shù) handleCallback(msg); } else { if (mCallback != null) { //如果Handler已設(shè)置callback,則調(diào)用該callback處理消息 if (mCallback.handleMessage(msg)) { //如果消息被處理 return; } } handleMessage(msg); //默認(rèn)為空函數(shù),用戶可重載處理自定義消息 } } private final void handleCallback(Message message) { message.callback.run(); } public Handler(Callback callback) { mLooper = Looper.myLooper(); //得到本線程的Looper對(duì)象 if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; } 用戶主要操作接口類Looper frameworks/base/core/java/android/os/Looper.java
public class Looper{ /** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ public static void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper()); } /** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ public static void prepareMainLooper() { prepare(); setMainLooper(myLooper()); myLooper().mQueue.mQuitAllowed = false; } public static void loop() { Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } long wallStart = 0; long threadStart = 0; msg.target.dispatchMessage(msg); //處理消息 } msg.recycle(); } } } 問題: 1.為了實(shí)現(xiàn)消息隊(duì)列等待機(jī)制,采用epoll方式來實(shí)現(xiàn)來消息時(shí)消息隊(duì)列處理線程的喚醒和當(dāng)無消息時(shí)線程掛起。實(shí)際上如果采用java對(duì)象wait/notify來實(shí)現(xiàn)此種功能更為簡單,,難道還有別的因素導(dǎo)致Google采用目前的設(shè)計(jì),? 分析:估計(jì)與IdleHandler有關(guān),目前當(dāng)消息隊(duì)列首次為空或取完所有消息后,,如果注冊(cè)了IdleHandler則會(huì)調(diào)用這些Handler處理,然后才會(huì)無限等待下一個(gè)消息到來 2.跨進(jìn)程消息傳送如何實(shí)現(xiàn):如鼠標(biāo)鍵盤事件傳遞 |
|