深入了解Handler消息机制(二)
来源:互联网 发布:淘宝天猫交易额 编辑:程序博客网 时间:2024/06/07 06:00
上一篇主要说了:
(1)Message,MessageQueue,Looper,Handler的工作原理就像是工厂的生产线。待加工的产品就是Message,“传送带”就是MessageQueue,电动机就是Looper,工人们就对应于处理事件的Handler。
(2)Android系统用链表来实现Message的缓存消息池。
我们知道Android的应用程序的入口是ActivityThread.main()方法。在该方法中首先会创建Application和默认启动的Activity,并且将他们关联在一起。而该应用的UI线程的消息循环也是在这个方法中创建的,具体代码如下:
public static void main(String[] args) { //代码省略 Process.setArgV0("<pre-initialized>"); //1,创建消息循环Looper,就是UI线程的Looper Looper.prepareMainLooper(); // 2,启动ActivityThread,这里最终会启动应用程序 ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // 3,执行消息循环 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }}
执行了ActivityThread.main方法后,应用程序就启动了,UI线程的消息循环也在Looper.loop函数中启动了。此后Looper就一直从消息队列中取消息,然后Handler处理消息。用户或者系统通过调用Handler不断地往消息队列中添加消息,这些消息不断地被取出、处理、回收,使得应用程序迅速地运转起来。
例如:我们在子线程中执行完耗时操作后通常需要更新UI,但我们都知道不能再子线程中更新UI。此时最常用的手段就是通过Handler将一个消息post到UI线程中,然后再在Handler的handleMessage方法中进行处理。
但是有一点要注意,就是如果用在不传递UI线程的Looper的情况下,那么该Handler必须在主线程中创建。
为什么必须这么做呢?
其实每个Handler都会关联一个消息队列,消息队列被封装在Looper中,而每个Looper又是ThreadLocal的,也就是说每个消息队列只会属于一个进程。因此如果一个Looper在进程A中创建,那么该Looper只能被该线程访问。而Handler则是一个消息投递,处理器,它将消息投递给消息队列,然后这些消息在消息队列中被取出,并且执行在关联在消息队列的线程中。默认情况下,UI线程也就是调用了Looper.getMainLooper方法,创建Looper之后最后会执行Looper.loop方法开启消息循环。
那么Handler是如何关联消息队列和线程的呢??
我们先看一下Hnadler的构造函数:
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 @Nullable Looper myLooper() { return sThreadLocal.get(); } public Handler(Callback callback, boolean async) { //代码省略 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;//获取消息队列 mCallback = callback; mAsynchronous = async; }
我们看到myLooper方法是通过sThreadLocal.get()来获得的。那么Looper对象又是在什么时候存进去的呢?在上面的源代码中我们发现prepare方法中创建了一个Looper对象并且将该对象设置给了sThreadLocal,这样队列就与线程关联上了。
我们再回到Handler中来,Looper属于某个线程,消息队列存储在Looper中,因此,消息队列就通过Looper与特定的线程关联上。而Handler又与Looper、消息队列关联,因此,Handler最终就和线程、线程的消息队列关联上了,通过该Handler发送的消息最终就会被执行在这个线程上。这就能解释上面提到的问题了,“在不传递Looper参数给Handler构造函数的情况下,用更新UI的Handler“必须在主线程中创建?”就是因为Handler要与主线程的消息队列关联起来,这样handlerMessage才会执行在UI线程中,更新UI才是被允许的。
创建了Looper之后,会调用Looepr的loop函数不断地从消息队列中取出消息。具体代码如下:
public static void loop() { final Looper me = myLooper();//获取Looper if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //通过Looper对象拿到消息队列 final MessageQueue queue = me.mQueue; // 代码省略 for (;;) {//死循环,即消息循环 Message msg = queue.next(); if (msg == null) { return; } //消息分发处理 msg.target.dispatchMessage(msg); //代码省略 //回收消息 msg.recycleUnchecked(); } }
从上述代码可以看出,loop方法其实就是建立一个死循环,容纳后通过从消息队列中逐个取出消息,最后就是处理消息,回收消息的过程。代码中调用的是MessageQueue的next函数获取下一条要处理的消息。这个MessageQueue在Looper的构造函数中构建。
- 深入了解Handler消息机制(二)
- 深入了解Handler消息机制(一)
- 深入了解android中的消息机制Handler
- handler消息机制了解
- Android源码解析Handler系列第(三)篇---深入了解Android的消息机制
- Handler消息机制源码解析(二)
- Android消息机制-Handler(二)
- Android消息机制深入了解
- 解析 Android 异步消息机制,深入了解 Handler、Looper、MessageQueue 关系
- android中的消息机制 了解Handler
- Android 消息机制--Handler机制(二)四大原理分析
- 深入理解Handler消息传递机制详解
- Handler消息机制(深入源码分析)
- Android开发Handler消息机制深入探究
- 深入解析Android中Handler消息机制
- 深入理解Android Handler 消息机制
- Android 中消息处理机制-Looper、Handler、Thread (二)
- Android 中消息处理机制-Looper、Handler、Thread (二)
- C# Winform工程省市县三级行政区联动1 --XML
- Phantomjs 调试方法
- 神经计算的软件整理
- 【集训队互测 2012】Middle
- oracle学习 第二章 限制性查询和数据的排序 ——02
- 深入了解Handler消息机制(二)
- Hbase之Java API使用
- [BZOJ1004] [HNOI2008] Cards - 群论,Burnside引理,Polya定理
- Toolbar的三个问题:修改左边箭头颜色、怎样修改右边以及子activity中的toolbar添加返回箭头
- java笔记——io流
- 了解数据库
- 关于百度,google map的url api的调用
- ubuntu安装pip+python27+ipython+scrapy+zlib-及遇到的各种问题解决
- java二分法查找