博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Looper,Handler,MessageQueue,Message之间的关系
阅读量:6298 次
发布时间:2019-06-22

本文共 10410 字,大约阅读时间需要 34 分钟。

hot3.png

Android异步消息机制架构:

Android异步消息处理架构,其实没那么复杂。简单来说就是looper对象拥有messagequeue,并且负责从messagequeue中取出消息给handler来处理。同时handler又负责发送messagelooper,由loopermessage添加到messagequeue尾部。就一个圈儿。下面给出图解:

87dacc16gw1f09d4z9fsgj20ij0csmxo.jpg

所以很明显handlerlooper是来联系在一起的。需要说明的是,多个message可以指向同一个handler,多个handler也可以指向同一个looper。还有一点很重要,普通的线程是没有looper的,如果需要looper对象,那么必须要先调用Looper.prepare()方法,而且一个线程只能有一个looper。调用完以后,此线程就成为了所谓的LooperThread,若在当前LooperThread中创建Handler对象,那么此Handler会自动关联到当前线程的looper对象,也就是拥有looper的引用。

Looper

Looper就是一个管理messagequeue的类。下面是这个类的源码。

public class Looper {    ......    private static final ThreadLocal sThreadLocal = new ThreadLocal();    final MessageQueue mQueue;//拥有的消息队列    ......    /**     * Initialize the current thread as a looper.     * This gives you a chance to create handlers that then reference     * this looper, before actually starting the loop. Be sure to call     * {@link #loop()} after calling this method, and end it by calling     * {@link #quit()}.     */    //创建新的looper对象,并设置到当前线程中    public static final void prepare() {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper());    }    ·····    /**     * Return the Looper object associated with the current thread.  Returns     * null if the calling thread is not associated with a Looper.     */    //获取当前线程的looper对象    public static final Looper myLooper() {        return (Looper) sThreadLocal.get();    }    private Looper() {         mQueue = new MessageQueue();         mRun = true;         mThread = Thread.currentThread();    }           ......}

调用完Looper.prepare()之后,在当前的线程创建的Handler才能拥有当前线程的looper。然后调用loop()来开启循环,处理message。下面是Looper类下的loop方法部分源码:

public static void loop() {    final Looper me = myLooper();//获取looper对象    if (me == null) {        //若为空则说明当前线程不是LooperThread,抛出异常        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");    }    final MessageQueue queue = me.mQueue;    获取消息队列    .....    for (; ; ) {        //死循环不断取出消息        Message msg = queue.next(); // might block (可能会阻塞)        if (msg == null) {            // No message indicates that the message queue is quitting.            //没有消息表明消息队列退出了            return;        }        // This must be in a local variable, in case a UI event sets the logger        //打印log,说明开始处理message。msg.target就是Handler对象        Printer logging = me.mLogging;        if (logging != null) {            logging.println(">>>>> Dispatching to " + msg.target + " " +                    msg.callback + ": " + msg.what);        }        //重点!!!开始处理message,msg.target就是Handler对象        msg.target.dispatchMessage(msg);//dispatchMessage:发送消息        //打印log,处理message结束        if (logging != null) {            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);        }        .....    }}

是一个大的循环,不断从消息队列出取出消息。然后调用一个很关键的方法msg.target.dispatchMessage(msg)开始处理消息。msg.target就是message对应的handlerlooper对象管理MessageQueue,从中取出message分配给对应的handler来处理。

Message

Message 就是一些需要处理的事件,比如访问网络、下载图片、更新ui界面什么的。Message拥有几个比较重要的属性。

         public int what 标识符,用来识别message

         public int arg1,arg2 可以用来传递一些轻量型数据如int之类的

         public Object obj Message自带的Object类字段,用来传递对象

         Handler target 指代此message对象对应的Handler

如果携带比价复杂性的数据,建议用Bundle封装,值得注意的地方是,虽然Message的构造方法是公有的,但是不建议使用。最好的方法是使用Message.obtain()或者Handler.obtainMessage() 能更好的利用循环池中的对象。一般不用手动设置target,调用Handler.obtainMessage()方法会自动的设置Messagetarget为当前的Handler。得到Message之后可以调用sendToTarget(),发送消息给HandlerHandler再把消息放到messagequeue的尾部。这个方法的源码如下:

/** * Sends this Message to the Handler specified by {@link #getTarget}. * Throws a null pointer exception if this field has not been set. */public void sendToTarget() {    target.sendMessage(this);//此处的target是message对应的Handler.}

Handler

它的构造函数如下:

/** * Default constructor associates this handler with the {@link Looper} for the * current thread. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. */public Handler() {    this(null, false);}/** * Constructor associates this handler with the {@link Looper} for the * current thread and takes a callback interface in which you can handle * messages. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * * @param callback The callback interface in which to handle messages, or null. */public Handler(Callback callback) {    this(callback, false);}/** * Use the provided {@link Looper} instead of the default one. * * @param looper The looper, must not be null. */public Handler(Looper looper) {    this(looper, null, false);}/** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. */public Handler(Looper looper, Callback callback) {    this(looper, callback, false);}/** * Use the {@link Looper} for the current thread * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages.  Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */public Handler(boolean async) {    this(null, async);}/** * Use the {@link Looper} for the current thread with the specified callback interface * and set whether the handler should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages.  Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */public Handler(Callback callback, boolean async) {    if (FIND_POTENTIAL_LEAKS) {        final Class
klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async;}/** * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. Also set whether the handler * should be asynchronous. * * Handlers are synchronous by default unless this constructor is used to make * one that is strictly asynchronous. * * Asynchronous messages represent interrupts or events that do not require global ordering * with respect to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * * @param looper The looper, must not be null. * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * * @hide */public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; //由此可知,它拥有looper对象,以及looper的messagequeue mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async;}

要通过Handler来处理事件,可以重写handleMessage(Message msg),也可以直接通过post(Runnable r)来处理。这两个方法都会在looper循环中被调用。

loop循环中处理信息的msg.target.dispatchMessage(msg)方法源码:

public void dispatchMessage(Message msg) {    //注意!这里先判断message的callback是否为空,否则就直接处理message的回调函数       if (msg.callback!= null) {  //这里的callback就是上面的Runnable        handleCallback(msg);    } else {        if (mCallback != null) {            //正是在这调用我们平常重写handleMessage            if (mCallback.handleMessage(msg)) {                return;            }        }        handleMessage(msg);    }}

首先判断是否用的是handler的post方法,如果是就执行r里面run()方法的代码,否则就判断handler的构造函数是否初始化了CallBack,是的话就会执行这个接口里面handleMessage(msg)方法,;如果放回的是false,最后就会调用handleMessage(msg)(建立handler时重写的方法,如果没有重写,就什么都不会执行)。下面是handler的post方法的源码:

/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is  * attached.  *   * @param r The Runnable that will be executed. *  * @return Returns true if the Runnable was successfully placed in to the  *         message queue.  Returns false on failure, usually because the *         looper processing the message queue is exiting. */public final boolean post(Runnable r){   return  sendMessageDelayed(getPostMessage(r), 0);//发送消息}

上面源码中getPostMessage(r)方法的源码:

private static Message getPostMessage(Runnable r) {    Message m = Message.obtain();    m.callback = r;  //就是上面的msg.callback,如果调用了handler的post方法,它就会不为空。    return m;}

上面的 if (msg.callback!= null) { //这里的callback就是上面的Runnable handleCallback(msg); }的handleCallback(msg)源码:(就是运行run方法里面的代码)

private static void handleCallback(Message message) {    message.callback.run();}

而 if (mCallback.handleMessage(msg)) { return; }中的handleMessage(msg)源码如下:

/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. * * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */public interface Callback {    public boolean handleMessage(Message msg);}

所以现在知道loop循环中处理信息的msg.target.dispatchMessage(msg)方法里面的代码了吧。

 

转载于:https://my.oschina.net/u/2987490/blog/1457253

你可能感兴趣的文章
Laravel5.0学习--01 入门
查看>>
时间戳解读
查看>>
sbin/hadoop-daemon.sh: line 165: /tmp/hadoop-hxsyl-journalnode.pid: Permission denied
查看>>
@RequestMapping 用法详解之地址映射
查看>>
254页PPT!这是一份写给NLP研究者的编程指南
查看>>
《Data Warehouse in Action》
查看>>
String 源码浅析(一)
查看>>
Spring Boot 最佳实践(三)模板引擎FreeMarker集成
查看>>
Fescar 发布 0.2.3 版本,支持 Redis 和 Apollo
查看>>
Google MapReduce到底解决什么问题?
查看>>
CCNP-6 OSPF试验2(BSCI)
查看>>
Excel 2013 全新的图表体验
查看>>
openstack 制作大于2TB根分区自动扩容的CENTOS镜像
查看>>
Unbuntu安装遭遇 vmware上的Easy install模式
查看>>
几个常用的ASP木马
查看>>
Mysql-5.6.x多实例配置
查看>>
psutil
查看>>
在git@osc上托管自己的代码
查看>>
代码大全读后感(二)
查看>>
HTTP协议
查看>>