美文网首页我爱编程
Android Handler 机制

Android Handler 机制

作者: GitViolet | 来源:发表于2018-04-12 12:44 被阅读0次

    Handler机制是Andrdoid中很常用的线程任务控制,Handler类负责信息传送和分发执行,Looper是控制Message中心,MessageQueue保持和提供Message。

    1、Message

    顺便提一下Message.obtain(),Message会维护一个信息池,以单列表结构存储,使用它可以减少对象的创建,节省内存,代码如下

     //池默认长度是MAX_POOL_SIZE=50
      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();
        }
        
        //执行完会进行回收
         void recycleUnchecked() {
            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的结构

    public final class Message implements Parcelable{
        public int what;
    
        public int arg1; 
    
        public int arg2;
    
        public Object obj;
    
        public Messenger replyTo;
    
        public int sendingUid = -1;
    
        int flags;
    
        long when;
        
        Bundle data;
        
        Handler target;//执行的Handler
        
        Runnable callback;//post时传入的灰度,会优先回调
        
        Message next;//链表结构
    }
    

    2、Handler

    Handler不管的post方法还是sendMessage,信息都是封装成Message传递执行,最终会调到sendMessageDelayed方法

     public final boolean sendMessageDelayed(Message msg, long delayMillis)
        {
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            //先计算运行的时间点,启动时间+延迟时间
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
    

    最后调用sendMessageAtTime插入到MessageQueue队列中

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

    Handler分发执行,优先级为:Runnable->Callback->handleMessage

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

    3、MessageQueue

    插入的代码会比较复杂,mMessage记录为信息队列的第一个

     boolean enqueueMessage(Message msg, long when) {
            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) {
                //判断线程的Looper是否停止
                if (mQuitting) {
                    IllegalStateException e = new IllegalStateException(
                            msg.target + " sending message to a Handler on a dead thread");
                    Log.w("MessageQueue", 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;
                }
    
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
    

    Looper会循环调用MessageQueue.next,获取Message执行

     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 (;;) {
                if (nextPollTimeoutMillis != 0) {
                    Binder.flushPendingCommands();
                }
    
                //本地方法,原来阻塞队列并设置唤醒时间
                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;
                    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) {
                            // 执行时刻未到,设置唤醒阻塞时间
                            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 (false) Log.v("MessageQueue", "Returning message: " + msg);
                            return msg;
                        }
                    } else {
                        // 没有信息
                        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);
                }
    
                // Run the idle handlers.
                // We only ever reach this code block during the first iteration.
                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("MessageQueue", "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;
            }
        }
    
    

    4、Looper

    以下是我们经常在线程启动Looper的代码,

    class LooperThread extends Thread {
            public Handler mHandler;
      
            public void run() {
                Looper.prepare();
      
                mHandler = new Handler() {
                    public void handleMessage(Message msg) {
                        // process incoming messages here
                    }
                }
                Looper.loop();
          }
        }
    

    先看一下prepare方法

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
    

    关键在ThreadLocal,ThreadLocal是线程报错数据的一种方式,Thread.threadLocals会记录保持在ThreadLocalMap中的key,下次要再根据key来获取数据,所以线程不一样,可以也不一样,获取Looper对象也不是同一个,所以其他不同线程使用不用Looper的效果

        //ThreadLocal.java
       public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);//获取当前线程的ThreadLocalMap
            if (map != null)
                map.set(this, value);//保存,
            else
                createMap(t, value);//创建
        }
        
           void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    

    创建Handler,会调用myLooper获取当前线程的Looper

     public static Looper myLooper() {
            return sThreadLocal.get();
        }
    
    

    Looper.loop()是一个无限循环的方法,不断获取MessageQueue中的信息进行执行,代码比较简单

    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;
    
            // 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 (;;) {
                Message msg = queue.next(); // 从消息队列获取信息,可能会阻塞
                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
                Printer logging = me.mLogging;
                if (logging != null) {
                    logging.println(">>>>> Dispatching to " + msg.target + " " +
                            msg.callback + ": " + msg.what);
                }
    
                //通过Handrle处理信息,
                msg.target.dispatchMessage(msg);
    
                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);
                }
    
                //回收Message
                msg.recycleUnchecked();
            }
        }
    
    ## 附
    MessageQueue 是在native层使用epoll进行阻塞和唤醒,有兴趣可以看下面的文章
    [Android消息机制Native](http://gityuan.com/2015/12/27/handler-message-native/)

    相关文章

      网友评论

        本文标题:Android Handler 机制

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