最近的工作涉及了Android的Handler消息传递,总结如下:
1. Handler :
为了实现线程和Activity中widget之间的通信,比如为了进行某些耗时操作而新开的线程,在这些操作中如果要跟新UI则需要Handler来处理。它主要负责Message的分发和实现不同Message操作的自定义,相当于句柄。
2. MessageQuene:
Message是线程和widget通信的介质,也就是来传递信息的,显然MessageQuene则是保存Message的列表,在代码中表现为ArrayList。
3. Looper:
是一个控制器,它不断的从MessageQuene中取Message,然后将Message传递给Handler中的handleMessage方法以实现用户自定义操作。
一个线程只能有一个Looper,线程中可能有多个Handler,一个Looper管理一个MessageQuene,不同线程的Looper由ThreadLocal管理。
整个工作流程如下:
1. 线程工作流程
线程注册Looper =>
线程注册Handler=>
Handler sendMessage 到 MessageQuene
2. Looper工作流程
在Looper.prepare()中Looper被注册 =>
Looper执行Looper.loop() 取MessageQuene中的Message,执行Message的Handler(句柄)的handlerMessage方法,实现自定义操作。 =>
Looper的管理通过ThreadLocal类实现,ThreadLocal机制:为不同线程管理变量副本,实现多线程异步操作。
源码分析如下:
1. 调用流程
- public class HelloAndroidActivity extends Activity {
- Handler handler = new Handler() {//根据返回Message自定义操作
- public void handleMessage(Message msg) {
- ......
- }
- }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Thread thread = new Thread() {
- public void run() {
- Looper.prepare();//注册Looper
- ........
- Looper.loop();//Looper开始操作MessageQuene
- handler.sendMessage(new Message());//发送消息到MessageQuene
- }
- };
- thread.start();//启动线程
- }
- }
2. Handler 分析
- /**
- * A Handler allows you to send and process {@link Message} and Runnable
- * objects associated with a thread's {@link MessageQueue}. Each Handler
- * instance is associated with a single thread and that thread's message
- * queue. When you create a new Handler, it is bound to the thread /
- * message queue of the thread that is creating it -- from that point on,
- * it will deliver messages and runnables to that message queue and execute
- * them as they come out of the message queue.
- */
- public class Handler {
- /**
- * Subclasses must implement this to receive messages.
- */
- public void handleMessage(Message msg) {
- }
- /** 初始化handler,确认Handler的mLooper, mQueue,callback等等<pre name="code" class="java"> * Use the {@link Looper} for the current thread with the specified callback interface</pre> * and set whether the handler should be asynchronous.<br>
- *<br>
- * Handlers are synchronous by default unless this constructor is used to make<br>
- * one that is strictly asynchronous.<br>
- *<br>
- * Asynchronous messages represent interrupts or events that do not require global ordering<br>
- * with represent to synchronous messages. Asynchronous messages are not subject to<br>
- * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.<br>
- *<br>
- * @param callback The callback interface in which to handle messages, or null.<br>
- * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for<br>
- * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.<br>
- *<br>
- * @hide<br>
- */<br>
- public Handler(Callback callback, boolean async) {<br>
- if (FIND_POTENTIAL_LEAKS) {<br>
- final Class<? extends Handler> klass = getClass();<br>
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&<br>
- (klass.getModifiers() & Modifier.STATIC) == 0) {<br>
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +<br>
- klass.getCanonicalName());<br>
- }<br>
- }<br>
- <br>
- <br>
- mLooper = Looper.myLooper();<br>
- if (mLooper == null) {<br>
- throw new RuntimeException(<br>
- "Can't create handler inside thread that has not called Looper.prepare()");<br>
- }<br>
- mQueue = mLooper.mQueue;<br>
- mCallback = callback;<br>
- mAsynchronous = async;<br>
- } /** * Handle system messages here. */在Looper.loop()中会调用这个函数,实现handle message public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } }
- handleMessage(msg); } } /** * Default constructor associates this handler with the queue for the * current thread. * * If there isn't one, this handler won't be able to receive messages. */ public Handler() { mLooper = Looper.myLooper();//获取该线程Looper if (mLooper
- == null) {//确保该线程已注册Looper throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = null; } /** * Returns a new {@link android.os.Message Message} from the global message
- pool. More efficient than * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this). * If you don't want that facility, just call Message.obtain() instead. */获取消息,比new效率高 public final Message
- obtainMessage() { return Message.obtain(this); } /** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return Returns
- true if the Runnable was successfully placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r),
- 0); } /** * Pushes a message onto the end of the message queue after all pending messages * before the current time. It will be received in {@link #handleMessage}, * in the thread attached to this handler. * * @return Returns true if the message was successfully
- placed in to the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */网MessageQuene中加入消息 public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * Remove any pending
- posts of messages with code 'what' that are in the * message queue. */ public final void removeMessages(int what) { mQueue.removeMessages(this, what, null, true); }}
- <pre></pre>
- <strong>3. Looper分析</strong>
- <p></p>
- <p></p>
- <pre name="code" class="java">/**
- * Class used to run a message loop for a thread. Threads by default do
- * not have a message loop associated with them; to create one, call
- * {@link #prepare} in the thread that is to run the loop, and then
- * {@link #loop} to have it process messages until the loop is stopped.
- */
- public class Looper {
- Thread mThread;
- private static Looper mMainLooper = null;
- /** 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()}.
- * 为进程注册Looper,并确保每个进程一个Looper,
- * ThreadLocal为不同进程分别管理相应Looper
- */
- public static final void prepare() {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper());
- }
- /**
- * Run the message queue in this thread. Be sure to call
- * {@link #quit()} to end the loop.
- * 不停的取message,并调用其Handler.
- */
- public static final void loop() {
- Looper me = myLooper();
- 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();
- while (true) {
- Message msg = queue.next(); // might block
- //if (!me.mRun) {
- // break;
- //}
- if (msg != null) {
- if (msg.target == null) {
- // No target is a magic identifier for the quit message.
- return;
- }
- if (me.mLogging!= null) me.mLogging.println(
- ">>>>> Dispatching to " + msg.target + " "
- + msg.callback + ": " + msg.what
- );
- msg.target.dispatchMessage(msg);
- if (me.mLogging!= null) me.mLogging.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();
- msg.recycle();
- }
- }
- }
- /**
- * Return the Looper object associated with the current thread. Returns
- * null if the calling thread is not associated with a Looper.
- * 获取当前线程Looper
- */
- public static final Looper myLooper() {
- return (Looper)sThreadLocal.get();
- }
- }</pre><br>
- <br>
- <p></p>
- <blockquote style="margin:0 0 0 40px; border:none; padding:0px">
- <p><br>
- </p>
- <p><br>
- </p>
- </blockquote>
- <br>
- <pre></pre>