Android -- Handler消息机制简析
来源:互联网 发布:linux下jdk怎么卸载 编辑:程序博客网 时间:2024/06/14 00:00
Android -- Handler消息机制简析
Android系统是消息驱动的。说到Android中的消息机制,就一定离不开这四个类:Handler、Message、Looper和MessageQueue,它们是Android消息机制的主要实现部分。我们首先先明确这四个类在消息机制扮演的角色,然后再一一对它们进行分析。
熟悉Android的同学应该知道了:
- Handler:消息的发送者;通过Handler对象可以将一个消息发送到某个线程所有的MessageQueue中
- Message:消息实体;通过Handler发送的消息对象
- Looper:一个消息循环,它为一个线程开启一个循环的消息队列
- MessageQueue:消息队列,在Handler机制中,一个线程只维护一个消息队列
Handler发送消息是发送到某个线程所持有的消息队列中,然后消息队列依据先进先出原则分别取出Message对象进行处理。那怎么能让线程能持有一个MessageQueue队列、并成为Looper线程呢?工作中,我们一般会这样做:
class MyThread extends Thread { public void run(){ Looper.prepare();//1 //... Looper.loop();//2 } }通过1、2两步,这个线程就成为了Looper线程。那这两步做了些什么呢?我们分别分析。
Looper.prepare():
/** 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() { 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)); }
// sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();sThreadLocal是Looper类的静态成员,类型是ThreadLocal。ThreadLocal对象在维护变量时,会为每个线程都维护一个副本;每个线程都只能持有自己的那一份,某个线程做修改操作也不会影响到其他线程持有的副本。Looper中这样实现,就保证了每个线程中只会有持有一个Looper对象。到这里可知,Looper::prepare()函数的作用就是为某个线程创建了一个Looper对象:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed);//在当前线程中创建消息队列 mThread = Thread.currentThread();//当前的线程对象 }这里做了两件事:
- 为当前线程创建了一个消息队列,保存在Looper对象中
- 在Looper对象中保存了一份当前线程的对象
再看Looper::loop()函数的实现,它的作用就是启动了当前的MessageQueue:
/** * 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();//sThreadLocal.get();从sThreadLocal获取自己的Looper对象 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue;//获取当前线程的MessageQueue对象 // 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();//开启一个死循环,不断地从queue中获得消息,并进行处理 for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg);//发送的消息对象为维护一个发送它的Handler的实例,调用该Handler的dispatchMessage()方法 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); } msg.recycleUnchecked(); } }在loop()函数中,我们会开启一个循环,不断地从消息队列中获取消息并进行处理。
当然我们也可以调用Looper.quit()函数停止当前的Looper线程:
/** * Quits the looper. * <p> * Causes the {@link #loop} method to terminate without processing any * more messages in the message queue. * </p><p> * Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. * </p><p class="note"> * Using this method may be unsafe because some messages may not be delivered * before the looper terminates. Consider using {@link #quitSafely} instead to ensure * that all pending work is completed in an orderly manner. * </p> * * @see #quitSafely */ public void quit() { mQueue.quit(false); }
到此,线程就已经持有了消息队列;使线程成为Looper线程的分析就结束了。
线程成为Looper线程后,我们要向MessageQueue中添加消息才有意义,这就要靠Handler对象了。要使用Handler发送消息,我们首先要创建Handler对象;查看它的构造函数:
线程成为Looper线程后,我们要向MessageQueue中添加消息才有意义,这就要靠Handler对象了。要使用Handler发送消息,我们首先要创建Handler对象;查看它的构造函数:
/** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */ public Handler(Looper looper) {// 1 this(looper, null, false); } /** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. */ public Handler(Looper looper, Callback callback) { // 2 this(looper, callback, false); } /** * Use the {@link Looper} for the current thread * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(boolean async) { // 3 this(null, async); } /** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(Callback callback, boolean async) { // 4 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()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; } /** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. Also set whether the handler * should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */ public Handler(Looper looper, Callback callback, boolean async) { // 5 mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }Handler有多个重载的构造函数,但最后都会调用到序号为4、5的多参的构造函数。从构造函数的实现我们可知,我们可以传入某个Looper,也可以使用当前线程默认的Looper;不同的Looper就代表着使用不同的MessageQueue。得到Handler对象后,我们就可以通过它来发送消息了。Handler中可以发送了两种类型的消息:一种是Runnable类型的,另一种是Message类型的。下面分别看一下这两种发送方式的实现过程。先看
/** * 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. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
最后的调用:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this;//把该Message对象的target设为this,代表当前发送消息的Handler if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);//将msg按延迟时间插入到消息队列中 }再看发送Runnable的形式:
/** * 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); }
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r;//赋值给Message::callback字段 return m; }可以看出,即使发送的是Runnable对象(代表某个任务),随后也会被封装成Message;最后将消息放进消息队列的过程两种形式是一致的。
Handler发送消息的过程我们也已经有了大致的了解,接下来就要看消息的处理过程了。
在讲Looper::loop()的时候,我们知道这时会开启一个循环,不断地从消息队列中获取消息,并交由对应的Handler去处理:
//开启一个死循环,不断地从queue中获得消息,并进行处理 for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } msg.target.dispatchMessage(msg);//发送的消息对象为维护一个发送它的Handler的实例,调用该Handler的dispatchMessage()方法 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); } msg.recycleUnchecked(); }其中
msg.target.dispatchMessage(msg);//发送的消息对象为维护一个发送它的Handler的实例,调用该Handler的dispatchMessage()方法就是消息的处理过程了。之前我们交过,我们在发送消息的时候,其中一步就是会将Message::target字段设置为当前发送消息的Handler对象。到此,我们就知道,一个消息的处理过程就是调用对应Handler的dispatchMessage()函数:
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) {//如果发送的是Runnable,消息发送过程中会设置callback字段 handleCallback(msg); } else { if (mCallback != null) {//构造Handler对象时传入了CallBack对象时,走该分支 if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);//Message消息处理分支 } }这里对Runnable和Message两种类型的消息处理做了区分。如果Handler发送的是Runnable,则:
private static void handleCallback(Message message) { message.callback.run(); }最后调用的是该Runnable对象的run()方法
如果发送的Message,则:
/** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }由我们创建Handler时覆盖的handleMessage(Message)函数处理。
如果mCallBack不为空,则表示我们在创建Handler时传入了CallBack参数,此时的处理也比较简单:
/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. * * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */ public interface Callback { public boolean handleMessage(Message msg); }调用CallBack对象的handleMessage()函数进行处理。
最后,Message比较简单;我们要注意的就是它提供的四个参数:
/** * User-defined message code so that the recipient can identify * what this message is about. Each {@link Handler} has its own name-space * for message codes, so you do not need to worry about yours conflicting * with other handlers. */ public int what; /** * arg1 and arg2 are lower-cost alternatives to using * {@link #setData(Bundle) setData()} if you only need to store a * few integer values. */ public int arg1; /** * arg1 and arg2 are lower-cost alternatives to using * {@link #setData(Bundle) setData()} if you only need to store a * few integer values. */ public int arg2; /** * An arbitrary object to send to the recipient. When using * {@link Messenger} to send the message across processes this can only * be non-null if it contains a Parcelable of a framework class (not one * implemented by the application). For other data transfer use * {@link #setData}. * * <p>Note that Parcelable objects here are not supported prior to * the {@link android.os.Build.VERSION_CODES#FROYO} release. */ public Object obj;具体的作用可以参考源码注释。最后,我们获取Message对象时,不要盲目地去创建新的Message,而是优先考虑调用Message::obtain()获取,这样会节省系统资源,更高效。
0 0
- Android -- Handler消息机制简析
- Android Handler消息机制
- android handler消息机制
- android handler消息机制
- Android Handler消息机制
- android handler消息机制
- android handler消息机制
- Android:Handler消息机制
- Android Handler 消息机制
- Android Handler消息机制
- android消息机制handler
- Android 消息机制--handler
- android消息机制-handler
- Android 消息机制Handler
- Android消息机制-Handler
- Android Handler 消息机制
- Android Handler消息机制
- Android消息机制Handler
- Android Studio插件开发实践--从创建到发布
- Hibernate 建立双向多对多关联关系
- 写给进军大数据的你们:
- MySQL聚合函数
- 【leetcode】63. Unique Paths II
- Android -- Handler消息机制简析
- C#随机函数Random()的用法
- [leetcode] Candy
- (备忘)myeclipse2014使用前的一些配置
- 第八周—鸡兔同笼
- 设计模式——建造者模式
- 个人MYSQL操作记录
- CLR无法从COM 上下文*****转换为COM上下文*****,这种状态已持续60秒。
- Activity生命周期详解