Handler、Looper、Message与HandlerThread
来源:互联网 发布:js div 自定义属性 编辑:程序博客网 时间:2024/04/28 19:04
Handler常用来更新UI。网上有很多讲解Handler的东西,我这就不多讲了,这里主要从源码入手讲一点更深的原理。
简单来讲,Handler的用法就是,用handler发出一个Message,然后handler的handleMessage()就会被调用,处理该Message。典型的使用场景就是子线程里做耗时操作(如下载图片),操作完成后,在子线程里用handler发出一个消息,在handleMessage()里更新UI。
handler发出的Message会被存进一个MessageQueue,有一个叫Looper的对象,不停的遍历这个Queue,取出里面的Message,然后交给发出这个Message的Handler,handler收到后就用handleMessage()来处理。而MessageQueue正是在Looper的构造方法里生成的,也就是---MessageQueue是Looper对象的一个实例变量
public final class Looper { ... ... final MessageQueue mQueue; final Thread mThread; ............ static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); /** * 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } 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(); } } ........ private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
每条线程,可以没有Looper对象,但最多只能有一个。主线程已经默认有一个,所以我们可以在主线程里直接自定义Handler来处理消息。如果在子线程里又该怎么使用Handler?
class MyHandlerThread1 extends Thread{ Handler handler; @Override public void run() { Looper.prepare(); handler=new Handler() { @Override public void handleMessage(Message msg) { //处理msg } }; Looper.loop(); } }
实际Looper对象是通过调用Looper类的静态方法prepare()生成的,因为Looper的构造方法是private的。最终prepare()方法是这样的
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就是一个Looper对象。不明白ThreadLocal的可以先去看看。Looper.loop()的作用就是开启对MessageQueue的遍历。遍历如下
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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } 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(); } }
通过for( ; ; )不停遍历。这么看来,那岂不要永远遍历下去了,没关系,关键在这里:
for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; }当queue返回null时,遍历也就结束了。什么情况下返回null呢?看MessageQueue源码:
Message next() { // Return here if the message loop has already quit and been disposed. // This can happen if the application tries to restart a looper after quit // which is not supported. final long ptr = mPtr; if (ptr == 0) { return null; } ............... // Process the quit message now that all pending messages have been handled. if (mQuitting) { dispose(); return null; } ........ }当ptr==0或者mQuitting的时候,沿着源码一步步分析,就会知道,能产生这两个效果的是程序退出或者直接调用looper的quit()方法。handler.getLooper().quit()之后,遍历也就终止了。
那么,消息又是怎么到达发出这个消息的Handler的呢?
注意:loop( )方法里的一句
msg.target.dispatchMessage(msg);
这个target正是发送这个msg的Handler,继续往下看就会发现,dispatchMessage最终调用了handler(或handler的callback)的handleMessage()。更详细的用法可以自己去看源码了。不禁想到一个问题,就是延时发送
handler.sendEmptyMessageDelayed(what,delayMillis)
究竟是消息先发送了出去等着时机到了再执行,还是等着时机到了才发送消息?
可以看到,是等着时机到了才发送消息。
由于是遍历一个Queue,然后调用handler的handleMessage()去执行,所以对于同一个handler来说,它的消息都是串行执行的,而且handleMassge()是在handler所在的线程里执行的。
HandlerThread是已经包装好了可以使用Handler的子线程。自己百度去吧。
阅读全文
0 0
- Handler、Looper、Message与HandlerThread
- Message,MessageQueue,Looper,Handler,HandlerThread
- Looper、Handler与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
- Android中的Looper、Handler与HandlerThread
- Android 的Handler、Looper与HandlerThread
- android Thread HandlerThread Looper Message MessageQueue Handler的关系
- android Thread HandlerThread Looper Message MessageQueue Handler的关系
- 安卓线程相关 HandlerThread Handler Thread Looper Message Runnable
- Android异步消息之Looper、Handler、Message、HandlerThread的关系
- Handler,Looper,Message,MessageQueue,HandlerThread使用总结(上)
- Looper、Message、Handler和HandlerThread之间的关系
- android Thread HandlerThread Looper Message MessageQueue Handler的关系
- Android HandlerThread、Handler、Looper、MessageQueue、Message 简单分析
- 从IntentService到HandlerThread再到Looper、Handler、Message
- git 常见使用命令
- Python学习笔记-17.09.22
- 1、Selenium + Python 实现 UI 自动化测试-环境搭建
- 通过JDBC进行简单的增删改查(以MySQL为例)
- 点的旋转算法
- Handler、Looper、Message与HandlerThread
- Java工厂模式(简单工厂、工厂方法、抽象工厂)
- SQLServer在日常使用中事物的开启与回滚、提交
- 管道流:(管道输入流 PipedInputStream与管道输出流 PipedOutputStream)
- HTTP协议详解
- spring-boot填坑
- 绝对定位 软键盘弹出时顶起底部按钮
- Python学习笔记:简单作业
- linux常用命令整理