您的位置:首页 > 运维架构

线程Looper+Handler+Thread学习

2015-08-18 15:31 344 查看
一. 相关概念

1. Message

1) 消息对象,就像是盛放消息的容器,Message Queue中的存放的对象。

2) 从MessagePool中获取Message对象有两种方法:Message.obtain()和handler.obtainMessage()。

3) 获取消息对象时并不一定是直接创建一个新的实例,而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例,则才用给定的参数创建一个Message对象

2. MessageQueue

1) 消息队列,存放消息的队列。

2) 一个线程最多可有一个MessageQueue。

3) 每一个MessageQueue都不能脱离Looper而存在,Looper是消息的管理者。

4) 除了主线程,在创建其他线程的时候,并不会自动创建其MessageQueue。通常新建一个Looper对象,然后由Looper.prepare()创建MessageQueue并对该线程的MessageQueue进行管理。

3. MessagePool

1) 线程池,存放空的消息Message。当Message中有消息时放在MessageQueue中,当没消息时就会被放入MessagePool中。

2) 存储结构为链表。

3) 默认线程池的大小是10,即可以存放最多10空的message。

4) 调用Handler.removeMessages()时,将Message从MessageQueue中删除,同时放入到Message Pool中。

5) 当消息分发完成后调用Message.recycle()回收消息,将其放入Message Pool中。

4. Looper

1) 循环(暂且理解为),MessageQueue的管理者。

2) 一个线程拥有一个Looper。主线程默认会创建一个Looper,Looper.getMainLooper () 获得主线程(UI线程)的Lopper。其他线程则通过 Looper.prepare()创建该线程的Looper对象;通过looper.myLooper()获得该线程的Looper对象。

3) 主线程自动创建一个Looper对象的同时也自动创建MessageQueue,其他线程通过Looper.prepare()创建该线程的MessageQueue。

4) 调用 Looper.loop()启动消息循环,之后就可以发消息、取消息、和处理消息等操作。

5) 当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler
对象收到该消息后,调用相应的handler 对象的handleMessage()方法,对其进行处理。

6) Looper负责从MessageQueue中取出消息,并且分发到消息指定目标Handler对象。

7) 退出时还要释放资源,调用Looper.release()。

5. Handler

1) 消息的处理者(只处理由自己发出的消息)。发消息,收消息,处理消息,移除消息(从MessageQueue中)。

2) 一个线程可以有多个handler,但只能有一个Looper。

3) Handler.obtainMessage()将消息封装成Message.

4) Handler.sendMessage()将消息发送给指定的Handler,继而由Looper将Message放入MessageQueue中。

5) Handler.handleMessage()接收消息,处理消息。

6) sendMessage()与handleMessage()的handler对象为同一个handler。若一个线程中有多个handler,如handlerA,handlerB,即使共同操纵同一个MessageQueue,它们也是不能进行通信的,handlerA得不到handlerB的消息。

7) Handler都是在主线程中的,也就是说,Handler类就都在主线程中运行,通俗的说就是“绑定”在主线程中,而不属于创建它的子线程。

8) 调用Handler.dispatchMessage()/msg.target.dispatchMessage(msg)分发消息。

9) 使用Handler对象的sendEmptyMessage或sendMessage方法来传递一个Bundle对象到Handler处理器

10) Handler.removeMessages(),将handler对应MessageQueue里的message删除,同时放入到MessagePool中;如果带了int参数则是对应的消息清空。队列里面没有消息则handler会不工作,但不表示handler会停止。

二. 消息传递机制

1、 初始化Looper

2、 绑定handler到Looper对象

3、 定义处理消息的方法

4、 启动消息循环

三. 备注

1. 子线程不能操纵主线程的控件。

2. Toast这种机制是不合view相关的,也不和activity相关的,不像dialog,取决于创建它的activity,Toast是由一种称为INotificationManager的服务管理的,所以虽然视图A虽然没有获取焦点,但是视图A对象仍旧在栈中,依旧存在,handlerA对象也存在,所以当他的到消息的时候,他依旧会去处理,弹出toast,Toast是一种很特别的机制,使用的时候一定要小心。

3. 要给哪个线程发消息,就要用该线程的Looper来创建handler,目的是创建消息队列MessageQueue。利用其handler来向其消息队列发送message

4. 处理消息时一定不要忘了开启消息循环,Looper.loop()。这样才能接收到多个消息。

5. 线程安全和线程不安全线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

四. 参考资源

1. http://www.eoeandroid.com/forum.php?mod=viewthread&tid=49595

2. http://blog.sina.com.cn/s/blog_49867dc001012ojl.html

3. http://blog.sina.com.cn/s/blog_629b701e0100rf45.html

这些博客资源对我受益匪浅,希望对大家有所帮助!

五. 源码

下载地址:http://download.csdn.net/detail/u013061822/9019737

六. 代码编写出错点

1. 在实现主线程向子线程发送消息时,不能正确显示收到的消息。打断点跟踪调试,发现子线程可以正确的收到消息,并把该消息发送给主线程,但是UI中textview中却没有显示收到的消息。推测可能是没有循环消息队列。添加Looper.loop()后正确显示!

2. 由第一个错误后,我把项目中每一个线程run()方法中都添加了Looper.loop()语句,当点击第二个按钮子线程向主线程发送消息时出错:08-18 14:44:10.363: E/AndroidRuntime(26101):java.lang.RuntimeException: No Looper; Looper.prepare() wasn't called on thisthread.出错截图:



大概是Looper为空,原来当子线程没有创建其本身的Looper时,是不能随便添加Looper.loop(),不能随便开启消息循环。如果一个线程需要接收消息的话则可以开启消息循环,如果只需要发送消息则不能开启消息循环队列。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: