线程间通信Handler,Looper,MessageQueue和Queue

来源:互联网 发布:mac怎么更改快捷键 编辑:程序博客网 时间:2024/05/21 22:24

为什么在工作线程中不能更新UI控件

  • Android系统对UI控件的更新采用的单线程模式,为什么要这样做?因为UI控件是线程不安全的,所以要对UI控件进行操作要进行异步处理。1,采用同步锁进行异步操作,这样的话,UI控件的更新效率会变低。2,采用只在UI线程对UI控件进行更新。所以是单线程模式。可以想象如果多个线程对UI控件进行更新,不采取异步处理,UI控件的状态是不是就不稳定了!
  • 如果工作线程要对UI控件进行更新,要使用Handler进行线程通讯,在UI线程上去更新

Message

  • Message是消息类,它的实例化可以new,但是官方源码建议使用obtain()来获得,它是一个消息池,上限是10个,一个Message对象可以循环使用,避免内存占用。总之它就一个放东西的口袋。
  • 属性有what-int类型存放消息类型
  • arg0,arg1-int型值,存放简单的整型
  • obj-Object类型,可以传递一些复杂的object
  • data-Bundle类型,数据很多的时候用它
  • callback:Runable型,下面讲Handler.post()会详细介绍

Looper

  • 主要方法就是prepare(),loop()
  • prepare()就是产生一个Looper对象,并且只能调要一次,产生Looper对象的时候也会产生一个MessageQueue对象,当然 MessageQueue也只有一个,调用两次的话会产生异常
  • loop()就是从MessageQueue中不停的取出消息,里面有一个死循环,死循环中有一个next()阻塞的死循环方法,也就消息队列中有消息的时候就会不停地去取,没有的话就会阻塞停止,知道有消息,取出消息后会调用处理消息的方法,这个方法会先去判断Message对象中的callback属性,判断是否为空,不为空就直接调用 handleCallback(msg);空的话就去会先查看mCallback是否存在,如果存在的话,尝试调用mCallback的handlerMessage方法,根据返回值决定是否再调用Handler的handlerMessage方法,而这个mCallback变量就是我们在新建handler时,传入的那个Runable对象。至此,消息处理的优先级就出来了:
    Message对象的callback>handler的Callback>Handler的handlerMessage

MessageQueue

  • 主要就是两个方法enqueueMessage(Message msg, long when)和next(),
  • 第一个方法是在Handler发送消息的时候调用
  • 第二个方法是个无限循环阻塞方法,在Looper.loop()中调用,其中Message中的When是在next中去处理的

Handler

  • sendMessage

    • 它是发送消息用的,sendMessage(Message msg),sendEmptyMessage(int what),sendMessageDelayed(Message msg, long delayMillis)最终都会调用sendMessageAtTime(Message msg, long uptimeMillis)方法,而这个方法会调用enqueueMessage(queue, msg, uptimeMillis)方法。
  • post

    • 它其实是将参数赋给Message的callback,所以它也是发送了一个消息

写在最后

总之就是,在一个线程中new出Handler,在其他线程使用这个Handler实例来发送消息,将消息发送到MessageQueue中(这里补充一点,这个消息队列是一个链表形式的,每一个消息都加在同一个链表上),然后使用Looper.loop()从消息队列中不断取出消息,将消息在传给Handler.hanldMessage去处理
1 0