android 消息系统Handler、MessageQueue、Looper源码学习

android消息系统

整体框架如图所示

在安卓的消息系统中,每个线程有一个Looper,Looper中有一个MessageQueue,Handler向这个队列中投递Message,Looper循环拿出Message再交由Handler处理。整体是一个生产者消费者模式,这四部分也就构成了android的消息系统。

先来看一个最简单的例子

        //这段代码在某个Activity的onCreate中
        Handler handler = new Handler(Looper.getMainLooper());
        Message msg = Message.obtain(handler, new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext,"I am a message",Toast.LENGTH_SHORT).show();
            }
        });
        handler.sendMessage(msg);

效果就是,在当前窗口弹出I am a message,当然就其实现的效果而言完全多此一举。但是就分析android消息系统,却是很简单有效的例子。


源码分析

Message

Message中封装了我们常用的what、arg1、arg2、obj等参数,除此之外还有target:一个Handler类型,由前文可知一个Message最终还是交给一个Handler执行的,这个target存放的就是消息的目的地、callback,一个消息的回调,我们通过handler.post(new Runnable{…})发送的消息,这个Runnable即被存为callback。

首先来看消息的获取:

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
    }

对照最开始的例子,Message.obtain(Handler h, Runnable callback)首先调用obtain获取了一个新的Message对象,然后为其设置了目的地Handler和回调函数callback,Message类中有很多不同的obtain函数,实际上只是为我们封装了一些赋值的操作。

再看Message.obtain()方法,sPoolSync是一个给静态方法用的静态锁,sPool是一个静态的Message变量,在消息的获取这里,android使用了享元模式,对于会被重复使用的Message消息,没有对每一次请求都新建一个对象,而是通过维护一个Message链表,在有空闲消息的时候从链表中拿Message,没有时才新建Message。

可以看到obtain中只有从链表中去Message和新建Message,而没有向链表中存储的过程。存储这部分就要看Message.recycle()了:

    public void recycle() {
        clearForRecycle();

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

回收过程,首先把原链表的头指向当前被回收消息的下一个节点,然后再把链表头指针知道当前节点即可。整个操作也就是将Message添加到链表的首位。


MessageQueue 消息队列

MessageQueue是在Looper中的,这点从Looper的构造函数可以看出来:

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

对于每个MessageQueue,是链表实现的消息队列。首先是入队操作:

boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg + " This message is already in use.");
        }
        if (msg.target == null) {
            throw new AndroidRuntimeException("Message must have a target.");
        }

        synchronized (this) {
            if (mQuitting) {
                RuntimeException e = new RuntimeException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            }

            msg.when = when;
            //mMessages是链表的头指针
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // 将消息插入到队列的首位
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    //当抵达队列尾部、或者当前消息的时间小于队列中某消息的时间跳出循环
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //将消息插入到链表中间(包含尾部)
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

next操作,包含取出和删除一条消息。

Message next() {
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            //从native层消息队列取出消息
            nativePollOnce(mPtr, nextPollTimeoutMillis);

            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // 找到非异步的Message或者消息队列尾部的Message取出
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // 消息尚未到执行时间,下次循环挂起线程一段时间
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // 获取一个Message
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (false) Log.v("MessageQueue", "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // 检查退出标志位
                if (mQuitting) {
                    dispose();
                    return null;
                }

                ...
        }
    }

Handler

Handler的作用是放入消息和处理消息,承担了生产者的工作和部分消费者的工作。

首先通过Handler发送一条消息:


public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

通过一层一层嵌套,真正的逻辑在sendMessageAtTime,可以看到仅仅是执行了一下入队操作。作为生产者的工作也就执行完成,消费者部分后面要结合Looper分析。

除了sendMessage方法,常用的handler.post方法也是封装为Message,主要过程和上面相似。

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

Looper

Looper类中,Looper的实例获取是通过ThreadLocal的,ThreadLocal会为每一个线程提供一个副本,通过set和get方法每个线程获取作用域仅属于该线程的变量值。对于UI线程而言,会执行Looper.prepareMainLooper()来完成Looper的初始化:


public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

Looper.prepare()方法将当前线程的ThreadLocal设置了一个新的Looper对象,prepareMainLooper则是把当前线程的Looper对象赋值给类变量sMainLooper ,该方法在ActivityThread中调用,设置了一个全局的给UI线程使用的Looper。

Looper的loop方法就是消费者的处理逻辑了:

public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn‘t called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        //从Looper中获取MessageQueue,循环取出消息
        for (;;) {
            Message msg = queue.next();

            ...

            //将消息发送给目标处理。
            msg.target.dispatchMessage(msg);

            ...

            //回收消息,把消息放在消息池中
            msg.recycle();
        }
    }

主要逻辑很清晰,前面分析过msg.target是一个Handler,表示处理消息的目标,通过命令模式将消息交给对应Handler处理。下面是Handler中处理消息的方法:

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

如果我们是通过handler.post的方法发送一条消息,那么直接执行callback中的逻辑。否则通过实现Callback接口回调,或者执行handleMessage,handleMessage也就是我们子类覆写的方法。可以看到,虽然逻辑部分是我们在Handler中实现的,但是调用的地方却是Looper的线程。因为一个Looper绑定一个线程,我们也可以通过比较Looper来比较线程。


总结

通过分析源码,可以知道android中可以通过Looper为每一个线程创建一个消息队里,UI线程的Looper在Activity启动前就已经初始化。那么对于我们自定义的线程,很明显也可以绑定Looper。

自定义线程绑定Looper,最明显的好处就是可以实现线程间通信了,同时由于借助了消息队列,也将并行转为串行实现了线程安全。看一个简单的例子:

        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                handlerA = new Handler(Looper.myLooper()){
                    @Override
                    public void handleMessage(Message msg) {
                        Log.d("TAG", msg.obj.toString());
                    }
                };
                Looper.loop();
            }
        }).start();

上述在线程中创建绑定了一个Looper,然后新建一个和当前Looper绑定的Handler,这样可以通过该Handler向Looper的MessageQueue中添加消息,然后由Looper.loop取出消息并执行。

        Message msg = new Message();
        msg.obj = "i am main thread";
        handlerA.sendMessage(msg);

在主线程或者其它线程中获取handler然后发送消息,最终可以看到消息被线程接收并处理。这里msg的target也就是handlerA。注意如果线程工作结束,需要调用Looper.quit(),不然会因为Looper一直循环而导致线程无法结束。

最后经过上面的分析,流程图可以画的更为细致:

时间: 2024-07-28 21:58:45

android 消息系统Handler、MessageQueue、Looper源码学习的相关文章

Android消息机制Handler解析(源码+Demo)

Handler是开发人员在面试过程中最常见的问题之一了,这篇文章将较为全面地对Handler进行解读,包括源码层,以及使用方法. 如果看完文章有疑问,欢迎在评论中一起探讨 基本内容包括: 看完文章之后,可以用这个图片进行复习. 一.什么是Handler Handler是Android提供用来更新UI的一套机制,也是一套消息处理机制,可以用它来发送消息,也可以用它来接收消息. 二.为什么使用Handler Android在设计之时,就封装了一套消息的创建.传递.处理机制,若不遵循这样的处理机制,就

从Handler+Message+Looper源码带你分析Android系统的消息处理机制

引言 [转载请注明出处:从Handler+Message+Looper源码带你分析Android系统的消息处理机制 CSDN 废墟的树] 作为Android开发者,相信很多人都使用过Android的Handler类来处理异步任务.那么Handler类是怎么构成一个异步任务处理机制的呢?这篇 博客带你从源码分析Android的消息循环处理机制,便于深入的理解. 这里不得不从"一个Bug引发的思考"开始研究Android的消息循环处理机制.说来话长,在某一次的项目中,原本打算开启一个工作线

Android消息机制Handler、Looper、MessageQueue源码分析

1. Handler Looper MessageQueue的关系 2.源码分析 下图表示了Handler.Looper.MessageQueue.Message这四个类之间的关系. Handler必须与一个Looper关联,相关Looper决定了该Handler会向哪个MessageQueue发送Message 每一个Looper中都包含一个MessageQueue Handler中的mQueue引用的就是与之关联的Looper的MessageQueue 不管Handler在哪个线程发送Mes

android 消息系统Handler、MessageQueue、Looper源代码学习

android消息系统 总体框架如图所看到的 在安卓的消息系统中,每一个线程有一个Looper,Looper中有一个MessageQueue,Handler向这个队列中投递Message,Looper循环拿出Message再交由Handler处理.总体是一个生产者消费者模式,这四部分也就构成了android的消息系统. 先来看一个最简单的样例 //这段代码在某个Activity的onCreate中 Handler handler = new Handler(Looper.getMainLoope

Android的Handler,Looper源码剖析

之前了解android的消息处理机制,但是源码看的少,现在把Looper,Handler,Message这几个类的源码分析一哈 android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因此我没将其作为核心类 Looper源码: Looper的字面意思是"循环者",它被设计用来使一个普通线程变成Looper线程.所谓Looper线程就是循环工作的线

【Android】Handler、Looper源码分析

一.前言 源码分析使用的版本是 4.4.2_r1. Handler和Looper的入门知识以及讲解可以参考我的另外一篇博客:Android Handler机制 简单而言:Handler和Looper是对某一个线程实现消息机制的重要组成部分,另外两个重要元素是Message和MessageQueue,通过这四个类,可以让某个线程具备接收.处理消息的能力. 二.源码剖析 虽然只有四个类,而且这里只是剖析其中两个,但是也不能独立分析,必须组合进行解析.切入点是类Looper的注释中的一段示例代码: 1

Android 调用系统相机以及相册源码

Android 调用系统相机拍照.以及相册.完成之后图片是上传到app上.前面的功能已经测试过了.没有上传到服务器,因为我没服务器测试.但项目里面有个类可以参考上传图片到服务器,我就没测试了.接下来看代码,虽然注释写得少,但其作用看英文单词意思,又在或是查看调用. 项目源码下载地址:http://download.csdn.net/detail/qq_16064871/8585169 转载请注明出处: http://blog.csdn.net/qq_16064871 package com.ex

[Android] 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析

1.Handler的由来 当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程. Android的UI操作并不是线程安全的(出于性能优化考虑),意味着如果多个线程并发操作UI线程,可能导致线程安全问题. 为了解决Android应用多线程问题-Android平台只允许UI线程修改Activity里的UI组建,就会导致新启动的线程无法改变界面组建的属性值. 简单的说:当主线程队列处理一个消息超过5秒,android 就会抛

Android源码学习-----Handler机制

Handler 1.为什么要使用Handler 在Android4.0之后,google公司为从系统使用及用户体验方面考虑,如果做一些比较耗时的操作,就不允许直接在主线程中进行,而是要通过handler发送Message对象的方法来修改主线程的UI界面 2.Handler原理简介 在所有的UI操作界面中,都在执行一个死循环(Looper)在不断接收和监听用户发出的指令,一但接受到指令,就立即执行.   当子线程需要修改UI界面时,调用Handler的sendMessage()方法,向主线程发送消