美文网首页
你真的了解Handler?

你真的了解Handler?

作者: Jarryd | 来源:发表于2017-04-10 11:03 被阅读0次

    Handler是Android中非常重要的线程间通信方式,所以我们今天用生活中类似的情况来谈谈Handler。看下大概流程图。

    Paste_Image.png
    Message——信
    数据类型 成员变量 解释
    int what 消息类别
    long when 消息触发时间
    int arg1 参数1
    int arg2 参数2
    Object obj 消息内容
    Handler target 消息目的地或者说处理者
    Runnable callback 回调方法
    获取Message实例——obtain()
      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();
        }
    
    MessageQueue——消息队列(邮箱)

    MessageQueue在该机制中充当类似邮箱的角色,它从Handler中接收消息,然后等待Loop取走,这一过程中没有对消息有任何更改。下面介绍下主要变量和主要函数。

    数据类型 成员变量 解释
    boolean mQuitAllowed 是否允许退出
    Message mMessages 消息队列,内部实现类似链表
    boolean mQuitting 是否已经退出
    boolean mBlocked 是否阻塞
    long mPtr 供native层方法使用
    //native层方法
    private native static long nativeInit();
    private native static void nativeDestroy(long ptr);
    private native void nativePollOnce(long ptr, int timeoutMillis);
    private native static void nativeWake(long ptr);
    private native static boolean nativeIsPolling(long ptr);
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
    
    构造函数
    MessageQueue(boolean quitAllowed) {  //是否允许退出
        mQuitAllowed = quitAllowed;
        //通过native方法初始化消息队列,其中mPtr是供native代码使用
        mPtr = nativeInit();
    }
    
    退出函数——quit(boolean safe)
    void quit(boolean safe) {
            // 当mQuitAllowed为false,表示不运行退出,强行调用quit()会抛出异常
            if (!mQuitAllowed) {
                throw new IllegalStateException("Main thread not allowed to quit.");
            }
            synchronized (this) {
                if (mQuitting) { //防止多次执行退出操作
                    return;
                }
                mQuitting = true;
                if (safe) {
                    removeAllFutureMessagesLocked(); //移除尚未触发的所有消息
                } else {
                    removeAllMessagesLocked(); //移除所有的消息
                }
            //唤醒消息队列,即从nativePollOnce()返回,使得next()可以往下执行
                nativeWake(mPtr); 
            }
        }
    
    提取消息——next()
    Message next() {
            final long ptr = mPtr;
    //如果已经调用quit()函数,直接返回
            if (ptr == 0) { 
                return null;
            }
            int pendingIdleHandlerCount = -1; //循环迭代的首次为-1
            int nextPollTimeoutMillis = 0;
            for (;;) {
                if (nextPollTimeoutMillis != 0) {
                    Binder.flushPendingCommands();
                }
    //阻塞操作,当等待nextPollTimeoutMillis时长,或者有新消息到达,都会退出该函数
                nativePollOnce(ptr, nextPollTimeoutMillis);
                synchronized (this) {
                    final long now = SystemClock.uptimeMillis();
                    Message prevMsg = null;
                    Message msg = mMessages;
                    if (msg != null && msg.target == null) {
    //当消息Handler为空时,查询MessageQueue中的下一条异步消息msg,则退出循环。
                        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 {
                            // 取回一条消息,并返回该消息
                            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 {
                      //没有消息
                        nextPollTimeoutMillis = -1;
                    }
                    if (mQuitting) {
                        dispose();
                        return null;
                    }
            //只有第一次进入循环时才进入下列循环 ps:pendingIdleHandlerCount = -1
                    if (pendingIdleHandlerCount < 0
                            && (mMessages == null || now < mMessages.when)) {
                        pendingIdleHandlerCount = mIdleHandlers.size();
                    }
                    if (pendingIdleHandlerCount <= 0) {
                       //没有idle handlers 需要运行,则循环并等待。
                        mBlocked = true;
                        continue;
                    }
                    if (mPendingIdleHandlers == null) {
             mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                    }
                    mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
                }
              //同样的,只有第一次循环时才下列循环,主要用于移除闲置的Handler
                for (int i = 0; i < pendingIdleHandlerCount; i++) {
                    final IdleHandler idler = mPendingIdleHandlers[i];
                    mPendingIdleHandlers[i] = null;
                    boolean keep = false; //标记Handler是否存活
                    try {
                        keep = idler.queueIdle();
                    } catch (Throwable t) {
                        Log.wtf(TAG, "IdleHandler threw exception", t);
                    }
                    if (!keep) {
                        synchronized (this) {
                            mIdleHandlers.remove(idler);//移除未保活的Handler
                        }
                    }
                }
              //设置空闲Handler数量为0,以保证不会再次重复运行
                pendingIdleHandlerCount = 0;
            //设置下次等待时长为0,以防在运行Handler时有新的消息到达
                nextPollTimeoutMillis = 0;
            }
        }
    
    存储消息——enqueueMessage(Message msg, long when)
    boolean enqueueMessage(Message msg, long when) {
          //如果message的targer或者说目的地为空,抛异常
            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) {
          //在退出时,回收msg,加入到消息池
                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);
                }
            }
            return true;
        }
    
    Looper——邮递员

    Looper负责将MessageQueue中的消息分发给对应的Handler,如果MessageQueue中没有消息,则阻塞,直到MessageQueue中有新的消息,或者退出循环。

    数据类型 成员变量 解释
    ThreadLocal sThreadLocal 类似Map,用于保存Looper实例
    MessageQueue mQueue 消息队列
    构造函数
    private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed); //实例化消息队列
            mThread = Thread.currentThread();
        }
    
    初始化函数——prepare()
    private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
            //根据所在线程从ThreadLocal获取Looper实例,
           //   注意,每个线程只能初始化一次
                throw new RuntimeException("Only one Looper may be created per thread");
            }
          //根据所在线程保存Looper
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
    循环函数——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;
              ......
            for (;;) {
              //从消息队列获取消息,此时可能因为MessageQueue处于阻塞而被阻塞
                Message msg = queue.next(); 
                if (msg == null) {
                    //如果返回msg == null,则退出循环,
                  //我们可以通过调用某些方法使得返回的 msg 为 null,然后退出循环
                    return;
                }
                .......
                final long traceTag = me.mTraceTag;
                if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                    Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
                }
                try {
                  //将msg 发送到目的地,并交给Handler处理
                    msg.target.dispatchMessage(msg);
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
                ......
                msg.recycleUnchecked(); //回收msg
            }
        }
    
    退出——quit()
    public void quit() {
          //通过调用MessageQueue的quit(),使其返回null,进而退出循环
            mQueue.quit(false); 
        }
    
    Handler——寄信人/收信人

    Handler扮演着既是寄信人,又是收信人的角色。

    数据类型 成员变量 解释
    Looper mLooper 对应线程的Looper
    MessageQueue mQueue 与mLooper相联系的消息队列
    Callback(接口) mCallback 用于处理消息的接口
    构造函数
    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;
        }
    
    写信——obtainMessage()
      //从消息池中获取一条消息,并将target(目的地)设为自己
     public final Message obtainMessage()
        {
            return Message.obtain(this);
        }
    
    寄信——sendMessageAtTime() & enqueueMessage()
    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);
            }
          //调用MessageQueue中的enqueueMessage(),将消息压入队列
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    
    public final boolean post(Runnable r)
        {
          //通过将Runnable包装成Message,并通过sendMessageAtTime方法发送
           return  sendMessageDelayed(getPostMessage(r), 0);
        }
    
      private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();
            m.callback = r;
            return m;
        }
    
    收信——dispatchMessage()
    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(); //调用message自身的处理方法
        }
     /**
         * 子类必须重写该方法才能对消息做相应的处理
         */
        public void handleMessage(Message msg) {
        }
    
    Message——信
    数据类型 成员变量 解释
    int what 消息类别
    long when 消息触发时间
    int arg1 参数1
    int arg2 参数2
    Object obj 消息内容
    Handler target 消息目的地或者说处理者
    Runnable callback 回调方法
    获取Message实例——obtain()
      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();
        }
    
    MessageQueue——消息队列(邮箱)

    MessageQueue在该机制中充当类似邮箱的角色,它从Handler中接收消息,然后等待Loop取走,这一过程中没有对消息有任何更改。下面介绍下主要变量和主要函数。

    数据类型 成员变量 解释
    boolean mQuitAllowed 是否允许退出
    Message mMessages 消息队列,内部实现类似链表
    boolean mQuitting 是否已经退出
    boolean mBlocked 是否阻塞
    long mPtr 供native层方法使用
    //native层方法
    private native static long nativeInit();
    private native static void nativeDestroy(long ptr);
    private native void nativePollOnce(long ptr, int timeoutMillis);
    private native static void nativeWake(long ptr);
    private native static boolean nativeIsPolling(long ptr);
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
    
    构造函数
    MessageQueue(boolean quitAllowed) {  //是否允许退出
        mQuitAllowed = quitAllowed;
        //通过native方法初始化消息队列,其中mPtr是供native代码使用
        mPtr = nativeInit();
    }
    
    退出函数——quit(boolean safe)
    void quit(boolean safe) {
            // 当mQuitAllowed为false,表示不运行退出,强行调用quit()会抛出异常
            if (!mQuitAllowed) {
                throw new IllegalStateException("Main thread not allowed to quit.");
            }
            synchronized (this) {
                if (mQuitting) { //防止多次执行退出操作
                    return;
                }
                mQuitting = true;
                if (safe) {
                    removeAllFutureMessagesLocked(); //移除尚未触发的所有消息
                } else {
                    removeAllMessagesLocked(); //移除所有的消息
                }
            //唤醒消息队列,即从nativePollOnce()返回,使得next()可以往下执行
                nativeWake(mPtr); 
            }
        }
    
    提取消息——next()
    Message next() {
            final long ptr = mPtr;
    //如果已经调用quit()函数,直接返回
            if (ptr == 0) { 
                return null;
            }
            int pendingIdleHandlerCount = -1; //循环迭代的首次为-1
            int nextPollTimeoutMillis = 0;
            for (;;) {
                if (nextPollTimeoutMillis != 0) {
                    Binder.flushPendingCommands();
                }
    //阻塞操作,当等待nextPollTimeoutMillis时长,或者有新消息到达,都会退出该函数
                nativePollOnce(ptr, nextPollTimeoutMillis);
                synchronized (this) {
                    final long now = SystemClock.uptimeMillis();
                    Message prevMsg = null;
                    Message msg = mMessages;
                    if (msg != null && msg.target == null) {
    //当消息Handler为空时,查询MessageQueue中的下一条异步消息msg,则退出循环。
                        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 {
                            // 取回一条消息,并返回该消息
                            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 {
                      //没有消息
                        nextPollTimeoutMillis = -1;
                    }
                    if (mQuitting) {
                        dispose();
                        return null;
                    }
            //只有第一次进入循环时才进入下列循环 ps:pendingIdleHandlerCount = -1
                    if (pendingIdleHandlerCount < 0
                            && (mMessages == null || now < mMessages.when)) {
                        pendingIdleHandlerCount = mIdleHandlers.size();
                    }
                    if (pendingIdleHandlerCount <= 0) {
                       //没有idle handlers 需要运行,则循环并等待。
                        mBlocked = true;
                        continue;
                    }
                    if (mPendingIdleHandlers == null) {
             mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                    }
                    mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
                }
              //同样的,只有第一次循环时才下列循环,主要用于移除闲置的Handler
                for (int i = 0; i < pendingIdleHandlerCount; i++) {
                    final IdleHandler idler = mPendingIdleHandlers[i];
                    mPendingIdleHandlers[i] = null;
                    boolean keep = false; //标记Handler是否存活
                    try {
                        keep = idler.queueIdle();
                    } catch (Throwable t) {
                        Log.wtf(TAG, "IdleHandler threw exception", t);
                    }
                    if (!keep) {
                        synchronized (this) {
                            mIdleHandlers.remove(idler);//移除未保活的Handler
                        }
                    }
                }
              //设置空闲Handler数量为0,以保证不会再次重复运行
                pendingIdleHandlerCount = 0;
            //设置下次等待时长为0,以防在运行Handler时有新的消息到达
                nextPollTimeoutMillis = 0;
            }
        }
    
    存储消息——enqueueMessage(Message msg, long when)
    boolean enqueueMessage(Message msg, long when) {
          //如果message的targer或者说目的地为空,抛异常
            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) {
          //在退出时,回收msg,加入到消息池
                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);
                }
            }
            return true;
        }
    
    Looper——邮递员

    Looper负责将MessageQueue中的消息分发给对应的Handler,如果MessageQueue中没有消息,则阻塞,直到MessageQueue中有新的消息,或者退出循环。

    数据类型 成员变量 解释
    ThreadLocal sThreadLocal 类似Map,用于保存Looper实例
    MessageQueue mQueue 消息队列
    构造函数
    private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed); //实例化消息队列
            mThread = Thread.currentThread();
        }
    
    初始化函数——prepare()
    private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
            //根据所在线程从ThreadLocal获取Looper实例,
           //   注意,每个线程只能初始化一次
                throw new RuntimeException("Only one Looper may be created per thread");
            }
          //根据所在线程保存Looper
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
    循环函数——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;
              ......
            for (;;) {
              //从消息队列获取消息,此时可能因为MessageQueue处于阻塞而被阻塞
                Message msg = queue.next(); 
                if (msg == null) {
                    //如果返回msg == null,则退出循环,
                  //我们可以通过调用某些方法使得返回的 msg 为 null,然后退出循环
                    return;
                }
                .......
                final long traceTag = me.mTraceTag;
                if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                    Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
                }
                try {
                  //将msg 发送到目的地,并交给Handler处理
                    msg.target.dispatchMessage(msg);
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
                ......
                msg.recycleUnchecked(); //回收msg
            }
        }
    
    退出——quit()
    public void quit() {
          //通过调用MessageQueue的quit(),使其返回null,进而退出循环
            mQueue.quit(false); 
        }
    
    Handler——寄信人/收信人

    Handler扮演着既是寄信人,又是收信人的角色。

    数据类型 成员变量 解释
    Looper mLooper 对应线程的Looper
    MessageQueue mQueue 与mLooper相联系的消息队列
    Callback(接口) mCallback 用于处理消息的接口
    构造函数
    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;
        }
    
    写信——obtainMessage()
      //从消息池中获取一条消息,并将target(目的地)设为自己
     public final Message obtainMessage()
        {
            return Message.obtain(this);
        }
    
    寄信——sendMessageAtTime() & enqueueMessage()
    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);
            }
          //调用MessageQueue中的enqueueMessage(),将消息压入队列
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    
    public final boolean post(Runnable r)
        {
          //通过将Runnable包装成Message,并通过sendMessageAtTime方法发送
           return  sendMessageDelayed(getPostMessage(r), 0);
        }
    
      private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();
            m.callback = r;
            return m;
        }
    
    收信——dispatchMessage()
    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(); //调用message自身的处理方法
        }
     /**
         * 子类必须重写该方法才能对消息做相应的处理
         */
        public void handleMessage(Message msg) {
        }
    
    总结
    • Handler通过sendMessageMessageQueue发送消息
    • Looper通过Loop不断向MessageQueue提取消息,没有消息时会阻塞
    • Looper通过将提取到的Message交给target处理
    参考资料

    Android消息机制1-Handler(Java层)

    相关文章

      网友评论

          本文标题:你真的了解Handler?

          本文链接:https://www.haomeiwen.com/subject/qaabgttx.html