Handler
Last updated
Was this helpful?
Last updated
Was this helpful?
以下是文档对handler的介绍及其翻译
A Handler allows you to send and processand Runnable objects associated with a thread's. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
通过handler可以将Message和Runnable对象发送并放置到期所在线程的MessageQueue队列当中。每一个Handler实例都会与单一的线程及其该线程的message队列关联。handler对象将会发送message或runnable对象到MessageQueue队列中等待被执行。
需要使用Handler有两大主要的原因:
在将来的某个时间点调度处理消息和runnable对象;
将需要执行的操作放到其他线程之中,而不是自己的;
调度处理消息是通过调用post(Runnable), postAtTime(Runnable, long),postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message),sendMessageAtTime(Message, long)和sendMessageDelayed(Message,long)等方法完成的。其中的post版本的方法可以让你将Runnable对象放进消息队列;sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列,然后交由handleMessage(Message)方法处理。(这个需要你复写Handler的handleMessage方法)。
在实际开发中主线程是不允许做耗时的操作的,通常耗时的操作都需要在子线程中进行,但却又只能在主线程中更新UI。为了解决这个问题通常都需要使用到Handler,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据),把这些消息放入主线程队列中,配合主线程进行更新UI。
Handler中分发消息的一些方法:
以上post类方法允许你排列一个Runnable对象到队列中,sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新。
以下的实例,功能为:通过线程修改界面TextView的内容:
要理解handler的原理必须要了解下面几个要素:
Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
通过构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
Message Queue(消息队列):用来存放线程放入的消息。
线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
ThreadLocal:用来保存某个线程中的数据
流程
一 创建消息
每一个消息都需要被指定的Handler处理,通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。消息的创建流程如图所示。
UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper,该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。 Handler、Looper、MessageQueue的初始化流程如图所示: Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用,子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。
UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。 子线程通过Handler、Looper与UI主线程通信的流程如图所示。