Android学习笔记之消息机制

时间:2023-03-08 19:08:35

Android的消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程。

  1.为什么要使用Handler?

Android规定访问UI只能在主线程中进行,如果在子线程中访问UI,则会抛出异常。同时Android建议不能在主线程中进行耗时的操作,不然会导致程序无法响应即ANR。因此耗时的工作只能交给子线程去做,而子线程却不能直接访问UI,为了解决这个矛盾,Android提供了Handler。Handler的主要作用是将某个任务切换到某个指定的线程中去执行。例如,我们在主线程中创建Handler,在子线程执行完耗时任务后,就可以通过Handler将更新UI的操作切换到主线程中去执行。

2.为什么系统不允许在子线程中访问UI?

因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。

3.Handler与MessageQueue,Looper

Android的消息机制主要是指Handler的运行机制,Handler的运行需要消息队列(MessageQueue)和消息循环(Looper)的支撑。

消息队列的内部存储结构并不是真正的队列,而是单链表。消息队列只是一个消息的存储单元,不能处理消息,而Looper就是来处理消息的。Looper会无限循环的去查看是否有消息,如果有,就处理,否则一直等待。

Handler创建时会采用当前线程的Looper来构造消息循环系统,如果当前线程没有Looper,则会报错(有的时候,也可以通过构造函数指定一个Looper)。这个当前线程的Looper是通过ThreadLocal来获取的。ThreadLocal并不是线程,它是线程内部的一个数据存储类,通过它可以在指定线性中存储数据和获取数据。

4.MessageQueue工作原理

         MessageQueue主要包含两个操作:插入和读取,分别对应enqueueMessage和next两个方法。enQueueMessage是往消息队列中插入一条消息,而next是从消息队列中取出一条消息并将其从消息队列中删除。前面说过,消息队列的内部实现是iyge单链表,它在插入和删除上比较有优势。

这里注意,next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞,当有新消息到来时,它会返回这条消息并将其从单链表中删除。

5.Looper的工作原理

  (1)Looper会一直不停的从MessageQueue中查看是否有消息,如果有,则会立刻处理,否则就一直阻塞。

为当前信线程创建Looper的方法如下:

new Thead("Thread1"){

  @override
public void run()
{
Looper.prepare();
Handler handler=new Handler();
Looper.loop();
}
}

注意,只有调用了Looper的loop方法后,消息循环系统才真正起作用。

loop方法会调用MessageQueue的next方法来获取消息,当没有消息时,next方法会阻塞,导致loop方法也会阻塞。Looper获得消息后,调用Handler对象的dispatchMessage方法,这个dispatchMessage方法是在创建Handler时所使用的Looper中执行的,这样就就将代码逻辑切换到指定的线程中去了。

loop方法是一个死循环,唯一跳出循环的方式是MessageQueue的next方法返回null。当Looper的quit方法被调用时,它会调用MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,其next方法就会返回null。

(2)Looper也可以退出,主要的方法是quit和quitSafely。前者会直接退出Looper,而后者只是设定一个标记,然后把消息队列中的已有消息处理完毕后才安全退出。Looper退出以后,Handler就无法再顺利发送消息了,其send方法会返回false。

(3)在子线程中创建Looper后,当所有事情完成以后应该调用quit方法来终止消息循环,否则这个子线程会一直处于等待状态。

  6.Handler的工作原理

Handler的主要工作是发送和接收消息。消息的发送通过post的方法和send的方法实现,post的方法最终是通过send的方法实现的。

Handler发送消息仅仅是向消息队列中插入一条消息,然后MessageQueue的next方法将消息给Looper处理,最终Looper将消息交给Handler处理,即Handler的dispatchMessage方法被调用。

public void dispatchMessage(Message msg){
if(msg.callback!=null)
{
handleCallback(msg);
}
else
{
if(mCallback!=null)
{ if(mCallback.handleMessage(msg))
{
return;
               }
}
handleMessage(msg);
}
}

这里msg.callback对象其实就是一个Runnable对象,就是Handler的post方法所传递的Runnable参数。

mCallback对应的类实现的是Callback接口。当我们不想派生Handler的子类并重写其handleMessage方法时,可以通过Callback来实现。