Handler 机制学习之相关类
2015-08-29 18:16
288 查看
1.Handler类
Handler主要负责发送消息和处理消息。
2.Looper类
3.Message类
4.MessageQueue类
/** * 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. * * <p>There are two main uses for a Handler: (1) to schedule messages and * runnables to be executed as some point in the future; and (2) to enqueue * an action to be performed on a different thread than your own. * <p>When posting or sending to a Handler, you can either * allow the item to be processed as soon as the message queue is ready * to do so, or specify a delay before it gets processed or absolute time for * it to be processed. The latter two allow you to implement timeouts, * ticks, and other timing-based behavior. * * <p>When a * process is created for your application, its main thread is dedicated to * running a message queue that takes care of managing the top-level * application objects (activities, broadcast receivers, etc) and any windows * they create. You can create your own threads, and communicate back with * the main application thread through a Handler. This is done by calling * the same <em>post</em> or <em>sendMessage</em> methods as before, but from * your new thread. The given Runnable or Message will then be scheduled * in the Handler's message queue and processed when appropriate. */体验下原汁原味~
/** * Subclasses must implement this to receive messages. 子类实现这个方法来处理消息 */ public void handleMessage(Message msg) { }
/** * Default constructor associates this handler with the {@link Looper} for the * current thread. *如果线程没有一个Looper,则不能接受消息,否则会有异常 * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */ public Handler() { this(null, false); }最终,调用的构造函数:
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()); } } mLooper = Looper.myLooper(); //得到当前Looper if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; //初始化MessageQueue对象 mCallback = callback; //初始化Callback对象 mAsynchronous = async; //是否异步 }
/** * 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. */ 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) //把一个Runnable对象加入到消息队列。 { return sendMessageDelayed(getPostMessage(r), 0); //getPostMessage:把Runnable对象转换成Message对象 }
/** * Causes the Runnable r to be added to the message queue, to be run * at a specific time given by <var>uptimeMillis</var>. * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> * The runnable will be run on the thread to which this handler is attached. * */ public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); }
public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); }
<pre name="code" class="java">//把Post中传入的参数Runnable对象转换成Message对象。
private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m; }
/** * 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); }
/** * Sends a Message containing only the what value. * * @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 sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 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); }
/** * Check if there are any pending posts of messages with code 'what' in * the message queue. */ public final boolean hasMessages(int what) { return mQueue.hasMessages(this, what, null); }
public final Looper getLooper() { return mLooper; }
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { //处理Runnable的消息 handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); //处理message消息 } }
private static void handleCallback(Message message) { message.callback.run(); //对于Runnable消息,不跑handleMessage,而是跑Runnable中的run方法 }
Handler主要负责发送消息和处理消息。
2.Looper类
/** * 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. * * <p>Most interaction with a message loop is through the * {@link Handler} class. * * <p>This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * * <pre> * class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * }</pre> */
/** 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) { //如果已经有一个Looper了的话就会报错。说明一个线程只能有一个Looper throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); //为当前线程创建一个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(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
/** Returns the application's main looper, which lives in the main thread of the application. */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } }
/** * 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(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final 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(); 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); //分发消息 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.recycle(); } }
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static Looper myLooper() { //得到当前线程的Looper return sThreadLocal.get(); }
/** * 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() { //结束当前的Looper<span style="font-family: 'Microsoft YaHei UI';">不要在本线程中调用quit()方法,因为永远都无法执行到这里。只能在其他线程调用。</span> mQueue.quit(false); }
/** * Return the {@link MessageQueue} object associated with the current * thread. This must be called from a thread running a Looper, or a * NullPointerException will be thrown. */ public static MessageQueue myQueue() { return myLooper().mQueue; }
private Looper(boolean quitAllowed) { //创建一个Looper,为私有构造方法,说明在外面不能创建一个Looper对象。 mQueue = new MessageQueue(quitAllowed); //创建Looper的时候就会创建MessageQueue。 mThread = Thread.currentThread(); }Looper主要负责管理线程中的消息队列(MessageQueue),取出消息,分发消息。
3.Message类
/** * * Defines a message containing a description and arbitrary data object that can be * sent to a {@link Handler}. This object contains two extra int fields and an * extra object field that allow you to not do allocations in many cases. * * <p class="note">While the constructor of Message is public, the best way to get * one of these is to call {@link #obtain Message.obtain()} or one of the * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull * them from a pool of recycled objects.</p> */
public final class Message implements Parcelable //实现了Parcelable接口
/** * 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;
/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { //得到一条消息。还有很多重载的 就不贴了 synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); }
/** * Return a Message instance to the global pool. You MUST NOT touch * the Message after calling this function -- it has effectively been * freed. */ public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
/** * Obtains a Bundle of arbitrary data associated with this * event, lazily creating it if necessary. Set this value by calling * {@link #setData(Bundle)}. Note that when transferring data across * processes via {@link Messenger}, you will need to set your ClassLoader * on the Bundle via {@link Bundle#setClassLoader(ClassLoader) * Bundle.setClassLoader()} so that it can instantiate your objects when * you retrieve them. * @see #peekData() * @see #setData(Bundle) */ public Bundle getData() { if (data == null) { data = new Bundle(); } return data; }
/** * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members * as a lower cost way to send a few simple integer values, if you can. * @see #getData() * @see #peekData() */ public void setData(Bundle data) { this.data = data; }Message类主要就是描述一条消息。
4.MessageQueue类
/** * Low-level class holding the list of messages to be dispatched by a * {@link Looper}. Messages are not added directly to a MessageQueue, * but rather through {@link Handler} objects associated with the Looper. * * <p>You can retrieve the MessageQueue for the current thread with * {@link Looper#myQueue() Looper.myQueue()}. */MessageQueue类就是消息队列。
相关文章推荐
- 如何选择开发板和保护开发板
- linux alias设置别名永久生效
- jquery 中 live事件委派 与 bind事件绑定
- POJ 2449 Remmarguts' Date (A*搜索求K短路)
- Mysql 总结
- Oracle 笔记之子查询
- nginx缓存优先级
- python2.7 beautifulsoup学习使用
- JAVA基础学习(一)--JAVA入门和JDK的安装与配置
- 山东省第六届ACM省赛 H---Square Number 【思考】
- express源码阅读
- [C#] 等待启动的进程执行完毕
- Oracle 笔记之高级查询
- python2.7 beautifulsoup安装下载
- UVA 10801 Lift Hopping (最短路)
- Linux CentOS 6.5 用户 常用命令
- C链表操作
- mongodb笔记
- HDFS架构——NameNode
- 往Linux内核添加系统调用