zoukankan      html  css  js  c++  java
  • android消息处理源码分析

    一、简介
    消息处理机制主要涉及到这几个类:
    1.Looper
    2.MessageQueue
    3.Message
    4.Handler

    二、源码分析

    Looper.class的关键源码:

    //保存Looper对象,在android中每创建一个消息队列,就有一个并且是唯一一个与之对应的Looper对象 
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    //主线程的Looper
    private static Looper sMainLooper;
    //消息队列
    final MessageQueue mQueue;
    final Thread mThread;
    
    //子线程中通过调用该方法来创建消息队列
    public static void prepare() {
        prepare(true);
    }
    
    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));
    }
    
    
    //主线程调用该方法来创建消息队列
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    
    //实例化Looper,创建消息队列,获取当前线程
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    
    //调用loop方法开启消息循环 
    public static void loop() { 
        //获取当前的Looper对象,若为null,抛出异常 
        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; 
        for (;;) { 
            //调用next()方法从消息队列中获取消息,如果为null,结束循环;否则,继续执行(有可能会阻塞) 
            Message msg = queue.next(); 
            if (msg == null) { 
                return; 
            } 
            ...... 
            try { 
                //调用handler的dispatchMessage(msg)分发消息  
                msg.target.dispatchMessage(msg); 
            } finally {
            ...... 
            } 
            //回收消息资源  
            msg.recycleUnchecked(); 
        }
    }
    
    //消息循环退出
    public void quit() {
        mQueue.quit(false);
    }
    
    public void quitSafely() {
        mQueue.quit(true);
    }

    消息循环退出过程

    从上面可以看到loop()方法是一个死循环,只有当MessageQueue的next()方法返回null时才会结束循环。那么MessageQueue的next()方法何时为null呢?

    在Looper类中我们看到了两个结束的方法quit()和quitSalely()。
    两者的区别就是quit()方法直接结束循环,处理掉MessageQueue中所有的消息。
    quitSafely()在处理完消息队列中的剩余的非延时消息(延时消息(延迟发送的消息)直接回收)时才退出。这两个方法都调用了MessageQueue的quit()方法

    MessageQueue.class 的关键源码:

    MessageQueue中最重要的就是两个方法:
    1.enqueueMessage()向队列中插入消息
    2.next() 从队列中取出消息

    /*
    *MessageQueue中enqueueMessage方法的目的有两个:
    *1.插入消息到消息队列
    *2.唤醒Looper中等待的线程(如果是即时消息并且线程是阻塞状态)
    */
    boolean enqueueMessage(Message msg, long when) {
        //发送该消息的handler为null,抛出异常
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        //此消息正在被使用
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }
    
        synchronized (this) {
            //此消息队列已经被放弃了
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                msg.recycle();
                return false;
            }
            msg.markInUse();
            msg.when = when;
            //消息队列的第一个元素,MessageQueue中的成员变量mMessages指向的就是该链表的头部元素。
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                //如果此队列中头部元素是null(空的队列,一般是第一次),或者此消息不是延时的消息,则此消息需要被立即处理,
                //将该消息作为新的头部,并将此消息的next指向旧的头部。如果是阻塞状态则需要唤醒。
                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;
                prev.next = msg;
            }
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
    
    Message next() {
        //与native方法相关,当mPtr为0时返回null,退出消息循环
        final long ptr = mPtr; 
        if (ptr == 0) {
            return null;
        }
    
        int pendingIdleHandlerCount = -1;
        //0不进入睡眠,-1进入睡眠 
        int nextPollTimeoutMillis = 0;  
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                //处理当前线程中待处理的Binder进程间通信请求
                Binder.flushPendingCommands();  
            }
            //native方法,nextPollTimeoutMillis为-1时进入睡眠状态
            //阻塞方法,主要是通过native层的epoll监听文件描述符的写入事件来实现的。
            //如果nextPollTimeoutMillis=-1,一直阻塞不会超时。
            //如果nextPollTimeoutMillis=0,不会阻塞,立即返回。
            //如果nextPollTimeoutMillis>0,最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回
            nativePollOnce(ptr, nextPollTimeoutMillis); 
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        //正常取出消息,设置mBlocked = false代表目前没有阻塞
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.更新到睡眠状态
                    nextPollTimeoutMillis = -1;
                }
    
                    // Process the quit message now that all pending messages have been handled.
                    if (mQuitting) {
                        dispose();
                        return null;
                    }
    
                    // If first time idle, then get the number of idlers to run.
                    // Idle handles only run if the queue is empty or if the first message
                    // in the queue (possibly a barrier) is due to be handled in the future.
                    if (pendingIdleHandlerCount < 0
                            && (mMessages == null || now < mMessages.when)) {
                        pendingIdleHandlerCount = mIdleHandlers.size();
                    }
                    if (pendingIdleHandlerCount <= 0) {
                        // No idle handlers to run.  Loop and wait some more.
                        mBlocked = true;
                        continue;
                    }
    
                    if (mPendingIdleHandlers == null) {
                        mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                    }
                    mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
                }
            }            
            //非睡眠状态下处理IdleHandler接口 
            for (int i = 0; i < pendingIdleHandlerCount; i++) { 
                final IdleHandler idler = mPendingIdleHandlers[i]; 
                // release the reference to the handler 
                mPendingIdleHandlers[i] = null; 
                boolean keep = false; 
                try { 
                   keep = idler.queueIdle(); 
                } catch (Throwable t) { 
                    Log.wtf(TAG, "IdleHandler threw exception", t); 
                } 
                if (!keep) { 
                    synchronized (this) { 
                        mIdleHandlers.remove(idler); 
                    } 
                } 
            } 
            pendingIdleHandlerCount = 0; 
            nextPollTimeoutMillis = 0;
        }        
    }

    Handler.class源码分析:

    /*
    *通过handler类向线程的消息队列发送消息,
    *每个Handler对象中都有一个Looper对象和MessageQueue对象
    */
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> 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());
            }
        }
        //获取Looper对象
        mLooper = Looper.myLooper(); 
        if (mLooper == null) {...}
        //获取消息队列
        mQueue = mLooper.mQueue;  
        mCallback = callback;
        mAsynchronous = async;
    }
    
    /*
    *多种sendMessage方法,最终都调用了同一个方法sendMessageAtTime()
    */
    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); 
    }
        
    /*
    *1.当Message中的callback不为null时,执行Message中的callback中的方法。这个callback时一个Runnable接口。
    *2.当Handler中的Callback接口不为null时,执行Callback接口中的方法。
    *3.直接执行Handler中的handleMessage()方法。
    */
    public void dispatchMessage(Message msg) {
        // 消息Callback接口不为null,执行Callback接口
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                //Handler Callback接口不为null,执行接口方法
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //处理消息
            handleMessage(msg); 
        }
    }
  • 相关阅读:
    FastJson的简单使用
    一些没用过的方法的学习
    Windows系统激活
    mysql数据库运行性能检查脚本
    基于windows 的Apache HTTP Server的一次小安装
    MySQL、Oracle批量插入、更新批量inisert、update
    IDEA中右键没有“Subversion”相关目录解决方法
    关于spring boot项目启动报错问题
    我的2016
    用intellij IDEA 编写时,无编程提示问题
  • 原文地址:https://www.cnblogs.com/lilykeke/p/10701429.html
Copyright © 2011-2022 走看看