Handler、Looper、Message源码解析
2016-07-13 16:37
357 查看
在Android中我们在使用异步消息处理时经常用到handler,looper,message。
1. Handler的介绍
一个Handler允许发送和处理线程消息队列中的消息和Runnable对象关联的进程。每个Handler实例都与一个单线程和该线程的消息队列关联。在创建一个新的Handler时,会绑定到创建它的线程的线程/消息队列上,它将传递message和runnable对象到消息队列并且能够执行消息队列中的消息。
下面我们看看源码
从上边代码我们可以看出,我们一般使用new Handler()实例化handler对象时,我们实际调用的是public Handler(Callback callback, boolean async)这个构造方法;
从14行中我们可以看到,通过Looper.myLooper()获取Looper实例,同时获取到MessageQueue实例.
值得注意的是:Can’t create handler inside thread that has not called Looper.prepare();提示我们在实例化Handler前,必须能调用Looper.prepa();
重写handleMessage(Message msg);
sendMessage()流程:
在这个方法中我们可以看到msg.target = this,就是将当前handler对象赋值给msg.target,下面的Looper中我们再次提到msg.target;
最后返回queue.enqueueMessage(msg, uptimeMillis),应该是将message对象和uptimeLillis延迟毫秒数放入当前线程的messagequeu队列中
我们经常使用handler.post(Runnable r)来更新UI界面,实际上它和sendMessage(Message msg)方法差不多,下面看看源码:
从源码中我们可以看出post(Runnable r)中的Runnable经过getPostMessage(r)转换成了Message,所以post(Runnable r)实际上还是和上边的sendMessage()相同
下面我们看一下dispatchMessage(Message msg)这个方法,因为它会在Looper.loop()中被msg.target(就是handler对象)调用,同时将Message对象传入,最终在handleMessage(Message msg)这个方法中我们获取到Message对象,执行我们所需要的操作
2. Looper的介绍
每个线程都有一个唯一的looper和MessageQueue,如果MessageQueue不为空,looper将会循环执行消息队列中的内容,否则阻塞.
prepare() 初始化当前线程中的一个looper,在这个方法后初始化handler,同时将该handler引用该looper,然后在调用Looper.loop()方法循环消息队列.
但是我们一般使用handler时,都是在类中直接定义使用,如下:
这是怎么回事呢?让我们来看一下这个方法:
从prepareMainLooper()的注释总我们可以看出,这个main Looper是由Android environment为application创建的,我们不需要创建就可以直接使用.但是我们在子线程中如果要初始化handler时,就必须先调用Looper.prepare()方法,在初始化handler之后调用looper.loop()方法来执行循环:
下面我们介绍一下loop()方法:
3.Message
Message是MessageQueue消息队列中所包含的对象,下面简单介绍一下:
我们在获取Message对象时最好通过Message.obtain()这个方法,因为这个方法可以避免多次new Message(),从而减少内存损耗.
关系图:
1. Handler的介绍
一个Handler允许发送和处理线程消息队列中的消息和Runnable对象关联的进程。每个Handler实例都与一个单线程和该线程的消息队列关联。在创建一个新的Handler时,会绑定到创建它的线程的线程/消息队列上,它将传递message和runnable对象到消息队列并且能够执行消息队列中的消息。
下面我们看看源码
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(); 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; }
从上边代码我们可以看出,我们一般使用new Handler()实例化handler对象时,我们实际调用的是public Handler(Callback callback, boolean async)这个构造方法;
从14行中我们可以看到,通过Looper.myLooper()获取Looper实例,同时获取到MessageQueue实例.
值得注意的是:Can’t create handler inside thread that has not called Looper.prepare();提示我们在实例化Handler前,必须能调用Looper.prepa();
重写handleMessage(Message msg);
public void handleMessage(Message msg) { // 对MessageQueue中取出的Message做处理 }
sendMessage()流程:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 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; // 如果当前MessageQueue为空抛出异常 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); }
在这个方法中我们可以看到msg.target = this,就是将当前handler对象赋值给msg.target,下面的Looper中我们再次提到msg.target;
最后返回queue.enqueueMessage(msg, uptimeMillis),应该是将message对象和uptimeLillis延迟毫秒数放入当前线程的messagequeu队列中
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
我们经常使用handler.post(Runnable r)来更新UI界面,实际上它和sendMessage(Message msg)方法差不多,下面看看源码:
public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } ......
从源码中我们可以看出post(Runnable r)中的Runnable经过getPostMessage(r)转换成了Message,所以post(Runnable r)实际上还是和上边的sendMessage()相同
下面我们看一下dispatchMessage(Message msg)这个方法,因为它会在Looper.loop()中被msg.target(就是handler对象)调用,同时将Message对象传入,最终在handleMessage(Message msg)这个方法中我们获取到Message对象,执行我们所需要的操作
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
2. Looper的介绍
每个线程都有一个唯一的looper和MessageQueue,如果MessageQueue不为空,looper将会循环执行消息队列中的内容,否则阻塞.
prepare() 初始化当前线程中的一个looper,在这个方法后初始化handler,同时将该handler引用该looper,然后在调用Looper.loop()方法循环消息队列.
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)); }
但是我们一般使用handler时,都是在类中直接定义使用,如下:
private Handler handler = new Handler(){ handleMessage(Message msg){ // 处理更新UI或者是.... } };
这是怎么回事呢?让我们来看一下这个方法:
/** * 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; } }
从prepareMainLooper()的注释总我们可以看出,这个main Looper是由Android environment为application创建的,我们不需要创建就可以直接使用.但是我们在子线程中如果要初始化handler时,就必须先调用Looper.prepare()方法,在初始化handler之后调用looper.loop()方法来执行循环:
Handler mHandler = null; public void get() { new Thread(new Runnable() { @Override public void run() { Looper.prepare(); mHandler = new Handler() { @Override public void handleMessage(Message msg) { } }; Looper.loop(); } }).start(); }
下面我们介绍一下loop()方法:
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ public static void loop() { // 获取当前线程中的looper对象 final Looper me = myLooper(); //如果looper为空,抛出异常 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } // 获取该looper中的messagequeue 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是handler对象,调用handler中的dispatchMessage(msg)方法,在dispatchMessage()中调用handleMessage(msg)来执行我们需要的操作 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.recycleUnchecked(); } }
3.Message
Message是MessageQueue消息队列中所包含的对象,下面简单介绍一下:
/*package*/ Handler target; //在上边我们介绍过 /*package*/ Runnable callback; // 在getPostMessage(Runnable r)个方法中用到过
我们在获取Message对象时最好通过Message.obtain()这个方法,因为这个方法可以避免多次new Message(),从而减少内存损耗.
关系图:
相关文章推荐
- OpenCV学习笔记(三):Canny边缘检测和滚动条制作
- 一天一条Linux指令-ln
- qss中使用自定义属性(property)
- Content Shell Apk分析之Content模块启动过程(上)
- Nginx获取自定义头部header的值
- Jenkins+docker实现应用发布
- docker 常用命令
- nginx如何设置自定义404页面
- Docker在Ubuntu的部署实践
- Powershell批量移除AD组成员
- Windows端Apache的域名映射
- Exchange2013 Get-MessageTrackingLog Powershell使用
- CentOS Linux中,使用sendEmail发送163邮箱的邮件
- linux配置Play Framework
- 部署LyncServer2013之二 扩展架构
- Windows管理员常用的PowerShell命令
- AD默认和扩展属性 Get-ADUser Default and Extended Properties
- 免费学桌面工程师、系统工程师、系统运维工程师
- Lync 2013常用Powershell总结
- Exchange 2010 PowerShell