android的消息机制之学习笔记

来源:互联网 发布:洛奇英雄传帧数优化 编辑:程序博客网 时间:2024/05/22 00:25

了解Android的消息机制,主要是了解handler,looper和MessageQueue的运行机制。

MessageQueue类

Message是消息的载体,MessageQueue则用来存放Message,虽说MessageQueue叫消息队列,其实它是由单链表实现的,因为单链表容易进行数据的增加和删除。

looper类

looper在安卓消息机制中主要扮演者消息循环的角色,在looper的构造方法中会生成 一个MessageQueue,looper则不断的循环检测这个消息队列,当检测到消息队列有新消息到来时,它会通知线程来读取并处理这个消息,否则它就一直阻塞在那里。一个线程对应着一个looper。

private Looper(boolean quitAllowed){    mQueue = new MessageQueue(quitAllowed);    mThread = Thread.currentThread();}

Handler类

handler是消息的接收者和处理者,通过handler,任务可以传递到另外一个线程进行处理。用户再源线程通过handler将消息传递到消息队列中,同时在目的线程通过handler的回调方法handleMessage()进行消息的处理。最常见的是将子线程中需要进行UI更新的任务传递到主线程进行处理。在安卓中,子线程是无法进行UI操作的,只能在主线程中进行UI的操作。这是因为UI控件不是线程安全的,在多线程并发访问的情况下会出现不可预期的状况。Android提供了handler,让我们统一的将各个线程的UI操作任务传递到主线程中进行。当然,handler不是专门用来进行UI操作的,只是大多数开发者常用handler进行UI操作。

整体分析

首先是创建handler对象。一个线程内可以用一个也可以用多个handler对象来进行处理消息。构造handler对象需要两个参数,一个是线程的looper对象,一个是消息的处理函数。handler只能对某一个线程的looper对象发送消息,所以必须指明looper参数,如果不指定looper对象,则默认使用当前线程的looper对象。另一个参数处理函数Callback则不是必须得。这个Callback 是Runnable类。构建完handler后就可以通过handler发送消息了,发送消息方法主要有两大类send和post。

public final boolean sendMessage(Message msg)  public final boolean sendEmptyMessage(int what)  public final boolean sendEmptyMessageDelayed(int what,long delayMills)  public final boolean sendMessageDelayed(Message msg,long delayMills)  public final boolean sendMessageAtFrontOfQueue(Message msg)  ...

这么多send方法归根到底就是把消息插入到消息队列中,并指定了时间。如果指定时间为0,则表示消息要理解处理,消息队列会吧这个消息插入到消息队列的头部。再看看post方法。

public final boolean post(Runnable r){    return sendMessageDelayed(getPostMessage(r),0);}public final boolean postAtTime(Runnable r,long uptimeMills){    return sendMessageAtTime(getPostMessage(r),uptimeMills);}...

可以看到,post方法归根是调用了send方法,只是它把消息处理函数封装到Message中了,一般,post方法用来发送带有处理方法的消息,send方法则用来发送传统的带有消息Id的消息。消息通过handler进行send发送后,会调用MessageQueue的enqueueMessage()方法。

boolean enqueueaMessage(Message msg,long when)

这个方法是干嘛的呢?它是将消息插入到MessageQueue中,它按照消息msg.when来排序,时间早的排在前面。它的源码主要操作就是单链表的插入操作。每插入一条消息,计算是否唤醒处理线程(看时间有没有到)。一个looper可以对应多个handler,所以MessageQueue中可以含有多个目的处理线程。那什么情况下会唤醒处理线程呢,MessageQueue中插入了一条马上要处理的消息,或者在暂停处理消息的情况下,又插入“异步消息”的情况下才会去唤醒处理的线程。那这个“异步消息”是什么消息呢?在Android的MessageQueue类中,有一个enqueueSyncBarrier(long when)方法,调用这个方法会在MessageQueue中插入一个没有handler对象的消息,这个不带handler对象的消息称为 ”SyncBarrier”,在“SyncBarrier”后面的消息都暂停处理。这个时候,如果使用 setAsynchronous()方法给一个消息做上标识,MessageQueue检测到这个标识后,还是会正常处理这个消息。这个设置了标识的消息就是所谓的”异步消息“。消息发送到MessageQueue后,looper就可以检测到这个新消息了。那么如何构建looper对象呢,系统会为主线程自动创建一个Looper对象,但是当用户创建一个子线程时,则需要用户亲自创建Looper对象了。Looper类中有一个静态方法prepare(),调用它会
创建一个Looper对象,并保存在ThreadLocal中,和当前线程绑定在一起。ThreadLocal 是一个模板类ThreadLocal,在Thread类中专门有一个成员用来存储ThreadLocal的数据,通过ThreadLocal就可以在指定线程中存储数据,这个数据数据对于其他线程来说是无法获取到的。在Looper类中,用ThreadLocal存储Looper对象,这样对于不同的线程,它的Looper对象是不一样的。创建了Looper对象后,就要loop()方法开启对其消 息队列的循环检测。这两个方法调用一般在线程的的run()方法中,如

class MyThread extends Thread{    public void run(){        Looper.prepare();        Looper.loop();    }}

loop()方法会循环从MessageQueue中取出消息,然后将消息分发个目的handler。

public static void loop(){    ...    for(;;){        Message msg = queue.next();        if(msg == null){            return;        }        ...        msg.target.dispatchMessage(msg);        ...    }}

loop()通过MessageQueue的next()方法取出消息,next()方法大概逻辑如下:

  • 检测MessageQueue第一条消息是不是”Syncbarrier”消息,如果是,寻找MessageQueue中第一个“异步消息”做完当前处理消息,如果不是,则将第一条消息作为当前处理消息。
  • 如果当前处理消息不为null,检测消息处理时间是否到了。如果没有,继续等待,如果到了,next()方法返回该消息并退出。
  • 如果当前处理消息为null,标示队列中没有可以处理的消息,设置等待时间为-1(表示永久等待)。通过next()方法取出消息后,就可以调用handler的dispatchMessage(msg)进行处理消息的。
public void dispatchMessage(Message msg){    if(msg.callback != null){        handleCallback(msg);    } else {        if(mCallback != null){           if(mCallbacl.handlerMessage(msg)){           return;         }         handlerMessage(msg);    }}

从源码可看出,消息给消息中自带的回调方法进行处理。如果消息中没有自带回调方法,且用户在handler定义了回调方法,则消息交给这个回调方法处理。否则,调用Handler自己的handlerMessage()的方法,这个方法缺省不做任何事。android消息机制java层处理将完了,对于其native层的实现,貌似是通过匿名通道来实现线程间通信的。这里不再讨论。

0 0
原创粉丝点击