在第一次启动一个Android程序时,Android会自动创建一个称为主线程的线程,即UI线程。该线程
主要是负责控制UI界面的显示、更新和控件交互。例如,在屏幕上按下一个按钮后,UI线程会把这个事件分
发给被按按钮,接着按钮设置它自身为被按下状态并向事件队列发送一个无效请求。UI线程会把这个请求移
出事件队列并通知按钮在屏幕上重新绘制自身。
在开发Android应用程序时必须遵守单线程模型的原则:Android UI操作并不是线程安全的并且这
些操作必须在UI线程中执行。因为所有的任务都会在同一个线程中执行,如果执行一些耗时的操作,如访问
网络或查询数据库,会阻塞整个用户界面。如果阻塞应用程序的时间过长,Android会打开一个应用程序没
有响应的对话框,向用户提示一些信息。
注意,不能通过使用子线程来更新由UI线程创建的视图,这违背了单线程模型的原则,系统会给出
CalledFromWrongThreadException异常提示。
MessageQueue
为了解决上面提到的界面阻塞问题,Android设计了一个Message Queue,线程间可以通过该
Message Queue并结合Handler和Looper组件进行信息交换。
Message:
Message消息,即线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据
给UI线程。
Handler:
Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线
程就是通过传进来的Handler对象引用来sendMessage(Message)。而使用Handler,需要实现该类的
handleMessage(Message)方法,它是处理这些Message的操作内容,例如更新UI。
大部分消息循环交互是通过Handler类,Handler可以看做是Looper的一个接口,用来向指定的
Looper发送消息及定义处理方法。默认情况下Handler会与其被定义时所在的线程的Looper绑定,因此,
mHandler=new Handler()等价于new Handler(Looper.myLooper())。
注意,在非主线程中直接new Hangler()会报错。
每个Handler都会与唯一的一个线程以及该线程的消息队列关联。当创建一个新的Handler时,默认
情况下,它将关联到创建它的这个线程和该线程的消息队列。因此,如果通过Handler发布消息的话,消息
将只会发送到与它关联的这个消息队列。当然也只能处理该消息队列中的消息。
主要的方法有:
public final boolean sendMessage(Message msg)把消息放入该Handler所关联的消息队列,放置
在所有当前时间未被处理的消息后。
public void handleMessage(Message msg)关联该消息队列的线程将通过调用Handler的
handleMessage方法来接收和处理消息。通常需要子类化Handler来实现handleMessage方法。
MessageQueue
MessageQueue是一个消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
每个消息队列都会有一个对应的Handler。Handler会向消息队列通过两种方法发送消息:
sendMessage和post。这两种消息都会插在消息队列队尾并按先进先出执行。但通过这两种方法发送的消息
的执行的方式略有不同:通过sendMessage发送的是一个message对象,会被Handler的handleMessage()方
法处理;而通过post方法发送的是一个runnable对象,会自己执行。
消息队列通常附属于某一个创建它的线程,可以通过Looper.myQueue()得到当前线程的消息队列
。Android在第一次启动程序时默认会为UI线程创建一个关联的消息队列,用来管理程序的一些上层组件,
可以在自己的子线程中创建Handler与UI线程通信。
Looper
Looper是每条线程里的MessageQueue的管家,扮演着一个Handler和消息队列之间通信桥梁的角色
。Looper对象通过MessageQueue来存放消息和事件,即程序组件首先通过Handler把消息传递给Looper,
Looper把消息放入队列。Looper也把消息队列里的消息广播给所有的Handler,Handler接收到消息后调用
handMessage进行处理。