Android 消息机制(Handler、Looper和MessageQueue)

背景

  1. 主线程不能执行耗时操作;
  2. 子线程完成了耗时操作,需要在UI上作出相应的改变;
  3. Android控件不是线程安全的,对其的操作只能在主线程进行,导致子线程无法访问UI;
  4. 消息机制帮助子线程“间接操作UI”。

概述

消息机制主要包含4个类

  • Message :消息的载体 ,可被复用;
  • MessageQueue: 用链表实现的消息队列,接收handler发送的消息,取出一个消息返回给Looper;
  • Handler :发送消息和处理消息;
  • Looper:不断 从MessageQueue中取出消息,并交给对应Handler处理;
  • 上图可以看到4个类之间互相持有对方的引用(标红部分),此文分析的重点就是4个类之间何时发生绑定关系。
  • Handler的创建

    默认方式
    private static class MyHandler extends Handler {
            @Override
            public void handleMessage(Message msg) {
               switch (msg.what){
    		case A:
    		 ...
    		 break;
    		case B:
    		 ...
    		 break;
    		 ...
    		default:
    		 break;
    		}
           }
    }
    
    private Handler myHandler2 = new MyHandler();
    
        public Handler() {
            this(null, false);
        }
    
        public Handler(Callback callback, boolean async) {
    		...
            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;
        }
    
    1. 绑定当前线程的Looper
    2. 绑定当前线程的消息队列
    3. 绑定mCallback
    Callback方式
        public Handler(Callback callback) {
            this(callback, false);
        }
    
        public interface Callback {
            public boolean handleMessage(Message msg);
        }
    

    Blockquote:
    * Callback interface you can use when instantiating a Handler to avoid
    * having to implement your own subclass of Handler.

    Looper方式
        public Handler(Looper looper) {
           this(looper, null, false);
       }
    
    • 方便获取指定线程的Handler

    Message的创建

       public final Message obtainMessage(){
           return Message.obtain(this);
       }
    
        public static Message obtain(Handler h) {
            Message m = obtain();
            m.target = h;//绑定handler
            return m;
        }
    
        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
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }
    
        /** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
        */
        public Message() {
        }
    
    • 新建Message对象最好使用obtain()方法,会优先从对象缓存池里获取,避免重复创建对象的开销。
    Message的复用
        public void recycle() {
            if (isInUse()) {
                if (gCheckRecycle) {
                    throw new IllegalStateException("This message cannot be recycled because it "
                            + "is still in use.");
                }
                return;
            }
            recycleUnchecked();
        }
    
    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) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool;
                    sPool = this;
                    sPoolSize++;
                }
            }
        }
    
    
    • 清空所有属性
    • 插入链表头部,将Message对象回收至对象池

    Message的发送

    消息发送由Handler完成,主要通过post方法(接收Runnable参数)和send方法(接收Message参数)执行,而post方法最终也是通过send方法实现。

    send方法的调用关系

    public final boolean sendMessage(Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    
    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;//mQueue为创建handler时所绑定的消息队列
        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; //绑定handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    

    post方法

        public final boolean post(Runnable r){
           return  sendMessageDelayed(getPostMessage(r), 0);
        }
    
        private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();
            m.callback = r;//将Runnable参数赋值给Message的callback属性
            return m;
        }
    

    插入消息到消息队列中

    boolean enqueueMessage(Message msg, long when) {
    		...
            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 p = mMessages;
                boolean needWake;
    			//直接插入到消息队列头部
                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 {
                    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);//有新的消息唤醒next()的阻塞
                }
            }
            return true;
        }
    
    • 消息队列中的消息按时间先后排序

    Looper的创建

        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");
            }//同一个线程的looper不能prepare两次
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);//绑定消息队列
            mThread = Thread.currentThread();//绑定当前线程
        }
    
    主线程的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();
            }
        }
    

    Blockquote :
    * The main looper for your application is created by the Android environment, so you should never need to call this function yourself.

        public static Looper getMainLooper() {
            synchronized (Looper.class) {
                return sMainLooper;
            }
        }
    
    • 获取主线程的Looper
    • 方便构建主线程的Handler

    消息的循环

    public static void loop() {
            final Looper me = myLooper();//从sThreadLocal中取出已初始化好的Looper
            if (me == null) {
                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;
                }
    			...
                msg.target.dispatchMessage(msg);
    			...
                msg.recycleUnchecked();
            }
        }
    
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    

    主要工作:

    • 从消息队列中取出消息
    • 交给对应Handler处理
    从消息队列中取出消息
    Message next() {
        ...
        for (;;) {
            ...
            //阻塞操作,当等待超时或者消息队列被唤醒,才会继续
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
               //如果msg.target==null,则一直循环msg = msg.next,直到msg.target不为null,msg.target其实是Handler
                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 {
                        // Got a message.
                        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;
                }
                ...
            }
            ...
        }
    }
    

    消息队列阻塞的条件:

    • 无消息
    • 有消息,但未到执行时间
    消息的处理
        public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);//处理post类型的message
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {//处理构建Handler时传入的CallBack
                        return;
                    }
                }
                handleMessage(msg);//子类Handler覆写的方法
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值