Handler Looper MessageQueue HandlerThread的那些事
来源:互联网 发布:毕向东java笔记百度云 编辑:程序博客网 时间:2024/06/05 19:18
概述:
Handler是Android系统提供的异步消息通信机制,在程序开发中,经常用到Handler在不同的组件之间发送消息,不同的线程之间也可以利用Handler通信,在Handler通信中,包含3个重要部分Handler,Looper,MessageQueue。
Looper创建消息队列:
在日常开发中,我们经常在UI线程中创建一个Handler对象,然后重写其handleMessage方法,在其他线程或者组件可以利用该Handler往UI线程中发送异步消息,回调相关方法进行处理,那么其内部是怎样工作的呢?
下面我们将分析UI线程中消息通信机制的运作过程。
消息处理机制中,所有消息都是由Handler发送到Looper创建的消息队列,Looper对象不停从消息队列中获取消息,最后分发给Handler处理
那么问题来了:
1,UI线程的消息队列怎样创建,并且进入消息循环
2,Handler如何将消息发送到消息队列
3,Looper从消息队列取到消息后又是怎样处理。
先来看一下UI线程中消息队列的创建过程。大家都知道,Android启动一个新的应用程序,会创建一个新的进程,执行ActivityThread的main函数,创建Looper消息队列,并进入消息循环。同时还会创建一个Handler对象,绑定到UI线程的消息队列,在Activity生命周期中,onCreate,onPause等方法都是由该Handler对象往UI线程发消息,最后调起来的。
public final class Looper { private static final String TAG = "Looper"; static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; 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)); } 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() { return sThreadLocal.get(); } public static MessageQueue myQueue() { return myLooper().mQueue; } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } /** * Return the Thread associated with this Looper. */ public Thread getThread() { return mThread; } /** @hide */ public MessageQueue getQueue() { return mQueue; }}
Looper类中sMainLooper即UI线程中的Looper对象,通过调用prepareMainLooper,最终会进入prepare函数,创建一个Looper对象,在Looper的构造函数中,创建一个消息队列。
调用loop()函数会进入消息循环,通过next函数获取消息,如果消息队列中没有消息,这里会阻塞,获取消息后通过msg.target.dispatchMessage(msg)将消息分发到Handler处理。
至此,UI线程中消息队列和循环的创建过程已经分析完毕,接下来我们再看Handler实现方式,Handler是怎样将消息发送到消息队列,以及从消息队列中取出消息后,Handler如何处理。
Handler:
public class Handler { private static final boolean FIND_POTENTIAL_LEAKS = false; private static final String TAG = "Handler"; public interface Callback { public boolean handleMessage(Message msg); } /** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { } /** * Handle system messages here. */ 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 {@link Looper} for the * current thread. * * 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) { this(callback, false); } public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } 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); } public final Looper getLooper() { return mLooper; }}
每个Handler对象必须关联一个Looper对象,Handler发送消息和接收消息都是基于这个Looper,Handler有多个构造函数,大致可以分为两类,含有Looper参数的和不含Looper参数的。含有Looper参数的构造函数,会使用参数传递的Looper对象,不含Looper参数使用当前线程中的Looper对象,如果线程没有创建一个Looper对象,则会抛出异常。
Handler关联一个Looper对象后,就可以往Looper对象创建的消息队列中发送消息,从源码来看,发送消息的方式有两种,一种是post,一种是send。
对于post方式,需要传入一个Runnable对象,这是一个回调对象,具体用途,在消息处理的时候再说,post传入runnable对象后,会调用gePostMessage方法构建一个msg,设置msg.callback为传入的runnable对象,最后调用send方式将消息发送到消息队列。所以,不管是post方法还是send方法,最后都是调用sendMessageAtTime,然后调用enqueueMessage方法,将消息放入到消息队列中。
消息发送到消息队列后,该如何处理呢。上面我们提到。Looper.loop()调用后,会不停的查询消息队列是否有消息,如果有,会调用msg.target.dispatchMessage()处理消息,msg.target即为发送该msg的Handler对象,dispatchMessage()方法中:
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
首先会判定msg.callback是否为空,这个msg.callback就是上面提到的post方式发送消息传入的Runnable对象,如果不为空,则调用handleCallback(msg); 这个函数里面会导致Runnable对象的run方法被调用。如果msg.callback为null,则判定mCallback是否为空,这个callback对象是Handler内部定义的接口,Handler构造函数可以传入一个Callback对象,如果Handler对象创建没有传入callback对象,那么mCallback为null,否则,调用该callback的handleMessage函数, 最后,调用Handler重写的handleMessage函数。整个过程可以用下面的时序图来表示。
上面分析了消息队列的创建与循环,Handler与Looper以及消息队列的关系,以及Handler如何发送和处理消息。可以用下面这个结构图来表示整个异步消息机制的运作流程
HandlerThread:
上面分析都是针对UI线程,如果我们想在自定义的线程中定义一个Handler,该怎么操作呢。
从上文分析可知,Handler对象必须依赖一个Looper对象,自定义线程中,并没有创建Looper对象。
有三种方式可以在自定义线程中创建Hander
1,使用带Looper对象的Handler构造函数,将主线程的Looper对象传入Handler构造函数中
Handler mHandler = new Handler(getMainLooper());
这种方式定义的Handler对象,使用了UI线程的消息队列,消息处理还是在UI线程中,和主线程中定义Handler,传入自定义线程没有任何区别。
2,自定义线程类,创建Looper对象,并且调用Looper.loop()方法开始消息循环。
3,使用HandlerThread类,这种方式其实就是第二种,只是Android系统已经帮我们做好了所有的工作,调用方便。
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } public Looper getLooper() { if (!isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; }
从HandlerThread的源码可以看到,实现方式和UI线程消息队列创建的方式类似,这里我们不再赘述。
HandlerThread类使用很简单:
HandlerThread ht = new HandlerThread("test");Handler mHandler = new Handler(ht.getLooper());mHandler.post(new Runnable() { public void run(){ Log.e("HandlerThreadTest", "test handlerThread");}}
Handler消息通信机制是Android系统提供的非常重要的组件,开发中,应用非常广泛,我们不仅要知其然,还要知其所以然,只有这样,才能真正掌握其用法。
PS:文章如有错误,欢迎大家提出意见,一起讨论,共同进步~
0 0
- Handler Looper MessageQueue HandlerThread的那些事
- Message,MessageQueue,Looper,Handler,HandlerThread
- Android-Handler 总结(Handler 的使用 ,Looper , MessageQueue , HandlerThread )
- Android-Handler 总结(Handler 的使用 ,Looper , MessageQueue , HandlerThread )
- android Thread HandlerThread Looper Message MessageQueue Handler的关系
- android Thread HandlerThread Looper Message MessageQueue Handler的关系
- Handler,looper,MessageQueue及 handlerThread 之间的关联和用法
- android Thread HandlerThread Looper Message MessageQueue Handler的关系
- 我理解的Handler,messageQueue,Looper,Messager,HandlerThread.
- Looper,Handler, HandlerThread,Message,MessageQueue分析
- [Android]Handler-Looper-MessageQueue-Message、HandlerThread
- Handler、Looper、MessageQueue、Message、HandlerThread以及ActivityThread
- 【java】Handler,Looper,Message,MessageQueue。【android】HandlerThread+Looper
- 对Handler,Looper,messagequeue,HandlerThread的深入理解,Handler常见面试题
- 从HandlerThread源码理清handler、looper与messageQueue之间的关系
- 解析android中的Looper MessageQueue Handler Thread HandlerThread类
- 从源码中深入学习Handler,HandlerThread,MessageQueue,Looper。
- 从源码中深入学习Handler,HandlerThread,MessageQueue,Looper。
- 数学基础之微积分
- 内核定时器
- Transact-SQL Cursor (数据库游标)
- MyEclipse 创建类时自动生成注释
- VS2012网站如何发布到服务器
- Handler Looper MessageQueue HandlerThread的那些事
- iOS_视图
- Spring - 自动获得对象的属性
- CF 297 div2 E. Anya and Cubes (hash+dfs)
- windowsphone 网络
- test
- 将Ubuntu 10.04自带2.6.32内核升级成3.0内核图文教程
- windowsphone 数据存储
- Linux epoll详解