Handler机制
来源:互联网 发布:创维32e300e数据 编辑:程序博客网 时间:2024/06/06 01:40
Android应用在启动的时候会开启一条主线程,也叫UI线程,在UI线程里面不能执行一些耗时操作,不然的话会使UI失去响应,会出现ANR。所以我们执行一些耗时操作(比如下载)的话需要另开子线程来执行,执行完成后可能需要更新UI(比如将下载下来的信息显示出来),但是Android只允许在主线程里面更新UI,因为UI线程是线程不安全的,这应该就是Handler机制产生的原因。
Looper、Handler、MessageQueue、
public static final void prepare() { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(true)); }
Looper.prepare()方法会判断ThreadLocal是否已经保存了Looper,是则抛出异常,这说明,一个线程只能有一个Looper(),为什么说一个线程只有一个Looper(),这个只有弄清楚了ThreadLocal的工作原理才能明白。
简单说一下就是:
sThreadLocal.set(new Looper(true))//其实等同于以下Thread.currentThread.ThreadLocalMap<ThreadLocal, Object>.put(sThreadLocal, Looper);
总结一下prepare()做的事情就是:判断当前线程是否已经有Looper了,有的话,抛出异常,没有的话,实例化一个Looper添加到ThreadLocal中,添加到ThreadLocal中,该Looper就和当前线程关联了。
对于ThreadLocal的理解可以参考http://blog.csdn.net/actor1999/article/details/52121303
获取Looper的方法,可以看到这个方法静态的。
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
Looper的构造方法,可以看到实例化了一个MessageQueue
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); }
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(); } }
可以看到,loop方法会执行一个死循环,从Message中取出数据 Message msg = queue.next(); 该方法可能会阻塞。当有Message的时候,调用msg.target.dispatchMessage(msg),这里的target是一个Handler对象,查看源码可以发现,该方法最终会调用handlerMessage()方法,而这个方法是个空方法,这也是我们处理消息的地方
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
我们在调用Handler.sendMessage(Message msg)其他方法也一样,最终都是调用以下这个方法:
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { boolean sent = false; MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } else { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); } return sent; }
可以看到这个方法就是设置msg.target = this.
然后调用queue.enqueueMessage(msg, uptimeMillsi),这个方法其实就是将消息加入队列中。
Handler在实例化的时候,会保存当前线程的Looper,和该Looper的MeesageQueue,因此在实例化Handler的时候要先调用Looper.prepare();
为什么Looper要这么设计,一个线程只能有一个Looper,并且其构造函数是private的,我们从他出现的背景就能够领悟一二,文章开头说过了,他出现的背景是,子线程想更新UI,但是子线程又不能更新UI,只能通过这种消息机制来通知主线程更新UI,或者具体到,它就是在当前线程检索是否有消息需要传递的一个东西,一个线程只需要有一个检索的就够了。
总结下来,整个流程就是:
- 调用Looper.prepare(),创建和线程绑定的Looper,还有和Looper绑定的MessageQueue。
- 实例化Handler,获取Looper和MeesageQueue。重写其handMessage()方法。
- 调用Hander.sendMessage()方法,这个方法会将Message加入MessageQueue队列
- 然后loop()方法会将消息取出来,然后调用msg.target.dispatchMessage(msg)(Meesage.Handler.dispachMessage())最终调用我们重写的handlerMessage()方法。(loop()里面是一个死循环)
- Handler机制
- Handler机制
- handler机制
- handler机制
- Handler机制
- Handler机制
- handler机制
- Handler机制
- handler机制
- Handler机制
- handler机制
- Handler机制
- Handler机制
- Handler机制
- handler机制
- handler机制
- Handler机制
- Handler机制
- uboot 简单的执行流程之我见
- ThreadPoolExecutor讲解
- EasyUI datagrid回车下一个
- android studio快速添加lambda的支持
- Jsoup发送get和post请求
- Handler机制
- 二叉树
- SQL临时表的使用
- [Lpp]如何安装配置PHP?
- Java 8+Android M新特性总结(简略版)
- wampserver2.5进入localhost了却进不去里面的项目文件夹
- jsp中session与application的区别
- git命令简单应用
- ubuntu刷新DNS