Handler 消息传递机制的理解与学习

UI线程
Android 程序首次启动时会同时启动一条主线程(Main Thread),主线程主要负责处理与 UI 相关的事件如按键事件、触屏事件、屏幕绘图事件等,并把相关事件分发到对应的组件进行处理。所以主线程又称 UI 线程。


出于性能考虑,Android 的 UI 操作并不是线程安全的,这意味着若有多个线程并发操作 UI 组件,可能会导致线程安全问题。因此 Android 平台只允许 UI 线程修改 Activity 里的 UI 组件。新启动的线程若需动态改变界面组件和属性值,只能借助于 Handler 消息传递机制来实现——这种机制可以看作是另一种形式的“事件处理”。


也就是说, Handler 消息传递机制,对于界面组件属性的修改,只授权给应用程序的主线程。其他线程若需改变界面组件属性,则只能给主线程发送消息(打申请),主线程会依次处理消息序列,并按相关规则执行或取消修改动作


Handler 类的认识


Handler 类的主要作用有两个:
在新启动的线程中发送消息。
在主线程中获取、处理消息。



这个类的使用及原理:


开发者重写 Handler 类中处理消息的方法;
当新启动的线程发送消息时,消息会被发送到与之关联的消息队列 MessageQueue;
Handler 会不断地从消息队列 MessageQueue 中获取并处理消息——这将导致 Handler 类中处理消息的方法被回调。


Handler 类包含如下方法用于发送、处理消息:
void handleMessage(Message msg) :处理消息的方法,通常用于被重写。
final boolean hasMessages(int what) :检查消息队列中是否包含 what 属性为指定值的消息。
final boolean hasMessages(int what, Object object) :检查消息队列中是否包含 what 参数为指定值且 Object 参数为指定对象的消息。
Message obtainMessage() :获取消息(多个重载)。
sendEmptyMessage(int what) :发送空消息。
final boolean sendEmptyMessageDelayed(int what, long delayMillis) :指定 delayMillis 毫秒之后发送空消息。
final boolean sendMessage(Message msg) :立即发送消息。
final boolean sendMessageDelayed(Message msg, long delayMillis) :指定 delayMillis 毫秒之后发送消息。



与 Handler 一起工作的几个组件:
Message :Handler 接收和处理的消息对象。
Looper :每个线程拥有一个 Looper。它的 loop 方法负责不断地读取 MessageQueue 中的消息,获取消息后分给对应的 Handler 进行处理。
MessageQueue :消息队列,采用先进先出的方式来管理 Message。程序创建 Looper 对象时会在 Looper 的构造器中创建与之关联的 MessageQueue 对象,这个 MessageQueue 就负责管理消息。
Handler :其作用有两个——把消息发送给 Looper 管理的 MessageQueue,并负责处理 Looper 分给它的消息。
为确保发送的消息能到达消息队列 MessageQueue,须先保证当前线程存在消息队列的创建者 Looper。处理方式分两种情况:
主 UI 线程中由系统初始化一个 Looper 对象,此时程序直接创建 Handler ,即可通过 Handler 来发送消息、处理消息。

程序员自己启动的子线程,须自己创建一个 Looper 对象并启动它。

创建方法:

prepare() :该方法会保证每个线程最多只有一个 Looper 对象。
然后调用 Looper 的静态方法 loop() 来启动它。



在线程中使用 Handler 的步骤如下:
调用 Looper 的 prepare() 方法为当前线程创建 Looper 对象。(此时 Looper 的构造器会自动创建与之关联的 MessageQueue)
创建 Handler 子类的实例,重写 handleMessage() 方法,以负责处理来自于其他线程的消息。
调用 Looper 的 loop() 方法启动 Looper。



注:执行需要消耗大量时间的操作一般应新开线程来执行,而尽量避免在 UI 线程中执行,否则容易导致 Android 应用程序无法响应输入事件和 Broadcast 而引发 ANR 异常(Application Not Responding)。




PS:
show.setImageResource(imageIds[currentImageId++% imageIds.length]);


上面这条代码,imagesIds 是一个数组,通过取余数的写法,可以不断的循环结构中不断的读取数组内容,而不用考虑数组越界的问题。

你可能感兴趣的:(学习笔记)