Android消息队列机制

相关文章
Android消息队列机制
IntentService中的耗时操作

C]
文章将带你理解 Looper、Handler、Message三者的关系。

一、基本用法

延时应用

定时器应用

//一个定时器
    private Handler handler = new Handler();  
  
    private Runnable myRunnable= new Runnable() {    
        public void run() {  
             
            if (run) {  
                handler.postDelayed(this, 1000);  
                count++;  
            }  
            tvCounter.setText("Count: " + count);  

        }  
    }; 

//然后在其他地方调用

handler.post(myRunnable);

handler.post(myRunnable,time);
    new Thread(new Runnable() {
            @Override
            public void run() {
                //在子线程post一个Runnable对象
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        //这里是消息处理的方法
                        //这里运行在主线程。
                    }
                });
            }
        }).start();

一个线程发送消息,另外一个线程接收信息

   //在主线程创建一个Handler对象。
    //重写Handler的handleMessage方法,这个就是接收并处理消息的方法。
    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            //msg就是子线程发送过来的消息。
        }
    };

    //开启一个子线程
    new Thread(new Runnable() {
            @Override
            public void run() {
                //在子线程发送一个消息。
                Message msg = new Message();
                handler.sendMessage(msg);
            }
        }).start();

 //声明Handler;
    Handler handler;
    new Thread(new Runnable() {
        @Override
        public void run() {
        //创建当前线程的Looper
            Looper.prepare();
            //在子线程创建handler对象
            handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                //这里是消息处理,它是运行在子线程的
                }
           };
           //开启Looper的消息轮询
           Looper.loop();
       }
   }).start();

   mBanner.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View v) {
       //在主线程发送一个消息到子线程
           Message msg = new Message();
           handler.sendMessage(msg);
       }
   });
//退出轮询
	Looper.myLooper().quit();
    Looper.myLooper().quitSafely();

获取主线程

Looper.getMainLooper()是获取主线程消息队列。

   new Thread(new Runnable() {
        @Override
        public void run() {
            //获取主线程的Looper
            Looper looper = Looper.getMainLooper();
            //用主线程的Looper创建Handler
            handler = new Handler(looper) {
                @Override
                public void handleMessage(Message msg) {
                //这里是运行在主线程的
                }
            };
        }
    }).start();

取消某个消息

handler.removeCallbacksAndMessages(null); //取消所有的回调方法和message

二、原理

Message

\frameworks\base\core\java\android\os\Message.java

public final class Message implements Parcelable {
 /**
     * User-defined message code so that the recipient can identify
     * what this message is about. Each {@link Handler} has its own name-space
     * for message codes, so you do not need to worry about yours conflicting
     * with other handlers.
     */
    public int what;

    /**
     * arg1 and arg2 are lower-cost alternatives to using
     * {@link #setData(Bundle) setData()} if you only need to store a
     * few integer values.
     */
    public int arg1;

    /**
     * arg1 and arg2 are lower-cost alternatives to using
     * {@link #setData(Bundle) setData()} if you only need to store a
     * few integer values.
     */
    public int arg2;

    /**
     * An arbitrary object to send to the recipient.  When using
     * {@link Messenger} to send the message across processes this can only
     * be non-null if it contains a Parcelable of a framework class (not one
     * implemented by the application).   For other data transfer use
     * {@link #setData}.
     *
     * <p>Note that Parcelable objects here are not supported prior to
     * the {@link android.os.Build.VERSION_CODES#FROYO} release.
     */
    public Object obj;

    /**
     * Optional Messenger where replies to this message can be sent.  The
     * semantics of exactly how this is used are up to the sender and
     * receiver.
     */
    public Messenger replyTo;

    /**
     * Optional field indicating the uid that sent the message.  This is
     * only valid for messages posted by a {@link Messenger}; otherwise,
     * it will be -1.
     */
    public int sendingUid = -1;

    /** If set message is in use.
     * This flag is set when the message is enqueued and remains set while it
     * is delivered and afterwards when it is recycled.  The flag is only cleared
     * when a new message is created or obtained since that is the only time that
     * applications are allowed to modify the contents of the message.
     *
     * It is an error to attempt to enqueue or recycle a message that is already in use.
     */
    /*package*/ static final int FLAG_IN_USE = 1 << 0;

    /** If set message is asynchronous */
    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

    /** Flags to clear in the copyFrom method */
    /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;

    /*package*/ int flags;

    /*package*/ long when;

    /*package*/ Bundle data;

    /*package*/ Handler target;

    /*package*/ Runnable callback;

    // sometimes we store linked lists of these things
    /*package*/ Message next;

    private static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50;

    private static boolean gCheckRecycle = true;
    
    public static Message obtain() {
        synchronized (sPoolSync) {
        	//如果消息池里面有空闲的消息可以用,则用消息池里面的。
            if (sPool != null) {
            	//当前这条信息取自消息池里面的复用
                Message m = sPool;
                //取出消息池的下一条未用信息
                sPool = m.next;
                //当前这条链路掐断
                m.next = null;
                m.flags = 0; // clear in-use flag
                //消息池内信息减1
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    /**
     * Same as {@link #obtain()}, but copies the values of an existing
     * message (including its target) into the new one.
     * @param orig Original message to copy.
     * @return A Message object from the global pool.
     */
    public static Message obtain(Message orig) {
        Message m = obtain();
        m.what = orig.what;
        m.arg1 = orig.arg1;
        m.arg2 = orig.arg2;
        m.obj = orig.obj;
        m.replyTo = orig.replyTo;
        m.sendingUid = orig.sendingUid;
        if (orig.data != null) {
            m.data = new Bundle(orig.data);
        }
        m.target = orig.target;
        m.callback = orig.callback;

        return m;
    }
    
    /**
     * Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
     * @param h  Handler to assign to the returned Message object's <em>target</em> member.
     * @return A Message object from the global pool.
     */
    public static Message obtain(Handler h) {
        Message m = obtain();
        m.target = h;

        return m;
    }

    /**
     * Same as {@link #obtain(Handler)}, but assigns a callback Runnable on
     * the Message that is returned.
     * @param h  Handler to assign to the returned Message object's <em>target</em> member.
     * @param callback Runnable that will execute when the message is handled.
     * @return A Message object from the global pool.
     */
    public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
    }

	    /**
     * Same as {@link #obtain()}, but sets the values for both <em>target</em> and
     * <em>what</em> members on the Message.
     * @param h  Value to assign to the <em>target</em> member.
     * @param what  Value to assign to the <em>what</em> member.
     * @return A Message object from the global pool.
     */
    public static Message obtain(Handler h, int what) {
        Message m = obtain();
        m.target = h;
        m.what = what;

        return m;
    }

	
    /**
     * Return a Message instance to the global pool.
     * <p>
     * You MUST NOT touch the Message after calling this function because it has
     * effectively been freed.  It is an error to recycle a message that is currently
     * enqueued or that is in the process of being delivered to a Handler.
     * </p>
     */
     //回收消息
    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }

    /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
        	//消息池里面只保留MAX_POOL_SIZE条空闲的信息,这些信息等待下次使用。
        	//如果实际消息池里面的数量还不够50条,则回收这一条信息,
            if (sPoolSize < MAX_POOL_SIZE) {
            	//当前这条信息连接好消息池里面空闲信息头
                next = sPool;
                //回收好当前这条信息
                sPool = this;
                //消息池内消息数量加1
                sPoolSize++;
            }
        }
    }
	......//还有set/get参数、序列化等等方法就不罗列了。
}

Message主要的实例属性是what ,arg1 ,arg2 ,obj,target,callback,next。what是主要是识别身份的,arg1,arg2是int参数,obj是传递的对象的,一般是作为令牌(token)来用,target是所用的handler。callback是Runnable, 需要的时候Run里面的任务。next是下一条message。message之间连成链式连接,这就是消息队列。消息队列是单向链表。
可以看到public static Message obtain()里面会根据原来有没有message来创建,如果有,拿出消息池里面的message出来用,sPoolSize–,如果没有则新建一条。message线程池的大小是50条,MAX_POOL_SIZE = 50。消息池实质是回收消息池,消息数目是可以超过50条的,只是消息池会回收最多50条用完的消息来存着备用。
obtain有好几个重载。

public static Message obtain(Handler h)
public static Message obtain(Handler h, Runnable callback)
public static Message obtain(Handler h, int what)
public static Message obtain(Handler h, int what, Object obj) 
public static Message obtain(Handler h, int what, int arg1, int arg2)
public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj)

可以根据自己需要创建不同参数的message。
recycle() 是回收message用的。

Handler

post

当用post发送Runnable 时候,它们是进行下面操作。
\frameworks\base\core\java\android\os\Handler.java

    /**
     * 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)
    {
    	//设置定时为0,用getPostMessage新建了一message
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    //这里新建了一个Mssage,然后把Runnable 放进去。
	private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
		
	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);
        }
        //调用消息队列里面的enqueueMessage,传进去消息和延时时间,这个实例里面传的是0.
        return queue.enqueueMessage(msg, uptimeMillis);
    }

消息队列处理
\frameworks\base\core\java\android\os\MessageQueue.java

	//消息排队,主要是刷选将要执行的消息,并把新消息入队。
    boolean enqueueMessage(Message msg, long when) {
    	//检查handler是否有
        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");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            //设置延时时间
            msg.when = when;
            //    Message mMessages;这个是链头,也相当于指针的作用了。
            Message p = mMessages;
            boolean needWake;
            //p == null 意味着到尾了。when == 0是立刻执行。when < p.when是比下一个message要早时间执行。
            //此时消息队列是有序排列的,按时间先后顺序。
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                //唤醒执行。设置当前消息为要执行消息。
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {//当前消息不是要将要执行消息。有其他消息需要先执行
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
               //Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
               //private boolean mBlocked;    
    
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                //这个主要是要找msge插入到队列的位置。
                for (;;) {
                	//用prev来指向当前队列的某个mssage,如果找到这个message将排在msg之前,p找下一个mssage
                    prev = p;
                    //找下链条里面的一个mssage,直到找完整个队列或者找到执行时间要比当前时间要长的。
                    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.
            //这里看是否唤醒线程循环,这里用到epoll技术
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

上面的操作已经把消息打入队列里面了。此时队列是有序排列的。

sendMessage

发送消息
\frameworks\base\core\java\android\os\Handler.java

    /**
     * Pushes a message onto the end of the message queue after all pending messages
     * before the current time. It will be received in {@link #handleMessage},
     * in the thread attached to this handler.
     *  
     * @return Returns true if the message 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 sendMessage(Message msg)
    {
    	//设置为0是立刻执行
        return sendMessageDelayed(msg, 0);
    }

    /**
     * Enqueue a message into the message queue after all pending messages
     * before (current time + delayMillis). You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     *  
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        //SystemClock.uptimeMillis()表示系统开机到当前的时间总数,单位是毫秒,
        //但是,当系统进入深度睡眠(CPU休眠、屏幕休眠、设备等待外部输入)时间就会停止,
        //但是不会受到时钟缩放、空闲或者其他节能机制的影响。
        //这里是延时加当前系统时间,表示未来要执行的时间点。
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    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);
    }

queue.enqueueMessage是根据放进去的消息来排列,上面已经说了原理。

postDelayed

基本原理和sendMessage一样

\frameworks\base\core\java\android\os\Handler.java

    public final boolean postDelayed(Runnable r, long delayMillis)
    {
	    //生成一个新的mssage,设置好延时毫秒
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }
    
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        //系统启动时间加要延时时间
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

	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);
    }

延时在消息从系统启动时间算起,看延时到哪个点,然后放到消息队列里面。

removeCallbacks

移除Callback
\frameworks\base\core\java\android\os\Handler.java

    /**
     * Remove any pending posts of Runnable r that are in the message queue.
     */
    public final void removeCallbacks(Runnable r)
    {
        mQueue.removeMessages(this, r, null);
    }

从消息队列里匹对消息然后移除该消息
\frameworks\base\core\java\android\os\MessageQueue.java

    void removeMessages(Handler h, Runnable r, Object object) {
        if (h == null || r == null) {
            return;
        }

        synchronized (this) {
        	//mMessages是消息队列的队首
            Message p = mMessages;

            // Remove all messages at front.
            //这里用循环来匹配消息内容,如果找到了,则把该条massage移除。
            //从队首开始删除,如果删除了队首就指向接下来的元素。
            while (p != null && p.target == h && p.callback == r
                   && (object == null || p.obj == object)) {
                   //令mMessages为下一个mssage 
                Message n = p.next;
                mMessages = n;
                //这里回收消息
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            //如果不为结尾继续循环,移除找到的Message
            while (p != null) {
                Message n = p.next;
                //如果下一条不是结尾还是有的话继续处理
                if (n != null) {
                	//匹配当前消息
                    if (n.target == h && n.callback == r
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

handler.removeCallbacksAndMessages(null);是用来清空消息队列的,此时匹对的消息的obj都是为null。

Looper

经过handler把消息压进了消息队列,需要一个循环逐一拿出来用,这个循环是Looper。在调用中用Looper.loop();来开启。

 //声明Handler;
    Handler handler;
    new Thread(new Runnable() {
        @Override
        public void run() {
        //创建当前线程的Looper
            Looper.prepare();
            //在子线程创建handler对象
            handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                //这里是消息处理,它是运行在子线程的
                }
           };
           //开启Looper的消息轮询
           Looper.loop();
       }
   }).start();

\frameworks\base\core\java\android\os\Looper.java

public final class Looper {
    /*
     * API Implementation Note:
     *
     * This class contains the code required to set up and manage an event loop
     * based on MessageQueue.  APIs that affect the state of the queue should be
     * defined on MessageQueue or Handler rather than on Looper itself.  For example,
     * idle handlers and sync barriers are defined on the queue whereas preparing the
     * thread, looping, and quitting are defined on the looper.
     */

    private static final String TAG = "Looper";

    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    //主线程调用的Looper
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;
    final Thread mThread;

    private Printer mLogging;
    private long mTraceTag;

    /* If set, the looper will show a warning log if a message dispatch takes longer than time. */
    private long mSlowDispatchThresholdMs;

     /** 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,Looper.prepare();每一个Looper对象会和一个线程关联 
      //Looper对象创建时会创建一个MessageQueue,一般其他线程要这个looper要调用Looper.prepare()
    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));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
	//这个主线程的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();
        }
    }

    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
     //这个是获取主线程的Looper,UI线程的大循环是这里取得
     //如果你想建立一个UI更新的handler,可以这么操作
     //Handler mhandler = new Handler(Looper.getMainLooper);
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
     //Looper.loop就是这个循环
    public static void loop() {
    	//sThreadLocal里面获取当前的ThreadLocal,其实是Looper对象。
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //获取当前Looper的消息队列
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
		//死循环
        for (;;) {
        	//查找下一条消息,消息队列里面保存有mMessages,这个是链头
            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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            //SystemClock.uptimeMillis() 从开机到现在的毫秒数(手机睡眠的时间不包括在内)
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
            	//这里调用的是handler里面的dispatchMessage(Message msg)方法,
            	//它将会调用我们自己定义的handleMessage方法。
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            //根据需要算时间差
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }
			//消息回收,这里的消息池内会回收消息。
            msg.recycleUnchecked();
        }
    }


    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
     //获取当前thread的threadload
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    /**
     * Return the {@link MessageQueue} object associated with the current
     * thread.  This must be called from a thread running a Looper, or a
     * NullPointerException will be thrown.
     */
     //获取threadload里面的消息队列
    public static @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }

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

    /**
     * Returns true if the current thread is this looper's thread.
     */
    public boolean isCurrentThread() {
        return Thread.currentThread() == mThread;
    }

    ......
}

大致的处理过程是获取当前线程的looper,然后获取looper里面的消息队列,然后一个个处理消息队列里面的消息,处理完就回收消息。

loop()里面的msg.target.dispatchMessage(msg);是调用了我们定义消息处理动作了。dispatchMessage里面是调用handleCallback或者handleMessage。dispatchMessage是Handler里面的方法。
\frameworks\base\core\java\android\os\Handler.java

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
    	//判断是否为空
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
        	//这里检查Callback 有没有被实现,如果有则调用改接口的handleMessage
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //这一步是调用我们定义的内容
            handleMessage(msg);
        }
    }
    
	//如果有callback则run,callback是一个Runnable
    private static void handleCallback(Message message) {
        message.callback.run();
    }

//handleMessage是我们定义的处理信息的动作了。
    /**
     * 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);
    }

    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    

看下Message msg = queue.next();里面执行了什么。
\frameworks\base\core\java\android\os\MessageQueue.java

public final class MessageQueue {
	Message mMessages;
	......
    Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
        	//这个nextPollTimeoutMillis 是上一次消息处理适合设置的下一次唤醒时间,没到时间就休眠
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
			//阻塞
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                //这里主要是检索吓一条mssage。如果找到就返回。
                //获取当前的时间。这个时间是系统开机时间,用毫秒表示。
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                //获取消息队列的头
                Message msg = mMessages;
                //如果handler没写好就一直找到下一个设置好target的message为止。
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    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 {
                        // Got a message.
                        //下一条信息到时间执行了,取出来。
                        mBlocked = false;
                        //如果该条信息还有前一条信息则设置好前一条信息的链路
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                        	//设置队列头为下一条信息
                            mMessages = msg.next;
                        }
                        //断开链路,单独取出来。
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    //没有消息了
                    nextPollTimeoutMillis = -1;
                }
                //消息都已经执行,并清空了。执行下面的流程。
                //其实是设置epoll的唤醒时间

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }
                //IdleHandler 可以用来提升性能,主要用在我们希望能够在当前线程消息队列空闲时做些事情
                //(譬如 UI 线程在显示完成后,如果线程空闲我们就可以提前准备其他内容)的情况下,不过最好不要做耗时操作。

                // 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);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            //循环遍历所有IdleHandler
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }
    ......
 }

MessageQueue.mMessages->( Message并且Message.next)-> ( Message并且Message.next)->…–>null 构成一个单向链表。Message msg = queue.next();是拿出下一条message出来,如果设置了定时,没到时间就会拿出来。拿出来后通过msg.target.dispatchMessage(msg);来执行。这个looper是个循环,有消息就处理,没消息就阻塞,通过epoll机制来调整运行状态。在塞信息进入消息队列适合会判断是否唤醒循环nativeWake(mPtr);

next里面的阻塞代码是下面这个。阻塞是发生在nativePollOnce方法,在native层使用了epoll机制来等待消息。

//private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
for (;;) {
    if (nextPollTimeoutMillis != 0) {
        Binder.flushPendingCommands();
    }
    nativePollOnce(ptr, nextPollTimeoutMillis);

    //...
}

退出消息队列

\frameworks\base\core\java\android\os\Looper.java

    /**
     * Quits the looper.
     * <p>
     * Causes the {@link #loop} method to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @see #quitSafely
     */
    public void quit() {
        mQueue.quit(false);
    }

    /**
     * Quits the looper safely.
     * <p>
     * Causes the {@link #loop} method to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * However pending delayed messages with due times in the future will not be
     * delivered before the loop terminates.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p>
     */
    public void quitSafely() {
        mQueue.quit(true);
    }

\frameworks\base\core\java\android\os\MessageQueue.java

    void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }
//可以从代码看出退出队列会把队列清空
    private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }

    private void removeAllFutureMessagesLocked() {
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            if (p.when > now) {
                removeAllMessagesLocked();
            } else {
                Message n;
                //如果队列头不是未来要执行的message的话,则继续找,找到为止。然后再回收那些未来某个点执行的message。
                for (;;) {
                    n = p.next;
                    if (n == null) {
                        return;
                    }
                    if (n.when > now) {
                        break;
                    }
                    //在链表里面找到不是立即执行的message,然后断开,再回收那些未来要执行的message
                    p = n;
                }
                //这里是为了链表断开那些定时和没定时的message
                p.next = null;
                //定时执行的message将被回收。
                do {
                    p = n;
                    n = p.next;
                    p.recycleUnchecked();
                } while (n != null);
            }
        }
    }

looper里面的quit()或quitSafely()可以退出消息队列,从代码看出退出队列会把队列清空。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章