美文网首页
Hander源码分析

Hander源码分析

作者: SunnyDay_ab5f | 来源:发表于2023-07-04 15:33 被阅读0次

    一、简介

    Handler是Android提供的一种消息机制。可以用来切换线程,实现线程间的通信。

    1.Handler的使用

    (1)handler的创建方式

           //废弃
            Handler handler = new Handler();
    
            //废弃
            Handler handler1 = new Handler(new Handler.Callback() {
                @Override
                public boolean handleMessage(@NonNull Message message) {
                    return false;
                }
            });
    
            //可以传入自己的Looper实例代替默认的Looper实例
            Handler handler2 = new Handler(Looper.getMainLooper());
    
            //你可以在实例化Handler时使用回调接口,以避免必须实现自己的Handler子类。
            Handler handler3 = new Handler(Looper.getMainLooper(), new Handler.Callback() {
                @Override
                public boolean handleMessage(@NonNull Message message) {
                    return false;
                }
            });
    

    另外我们在开发时会经常用到一种错误的使用方式非静态匿名内部类。

             //匿名内部类会造成泄漏,应该使用静态内部类,并把外部类的弱引用在初始化时传入Handler这样内部类就可以使用外部类的成员变量
            Handler handler4 = new Handler(){
                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg);
                }
            };
    

    如果使用这种方式AS会提示有内存泄漏的风险造成外部类无法被回收,但是如果handler在主线程以外的线程中使用Looper和MessageQueue则没有问题。

    如下图AS的提示


    handler.png

    (2)按照提示Handler在外部类中的正确使用方式应该如下:

     public static class TestHandler extends Handler{
            private WeakReference<MainActivity> mActivity = null;
            public TestHandler(MainActivity activity) {
                mActivity = new WeakReference<MainActivity>(activity);
            }
    
            //子类必须实现此方法才能收到消息
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                MainActivity mainActivity = mActivity.get();
                if (mainActivity != null){
                    //do something
                }
            }
        }
    
    

    如果不想实现自己的handler直接使用这个构造函数即可,没有匿名内部类不会存在泄漏

     Handler handler3 = new Handler(Looper.getMainLooper(), new Handler.Callback() {
                @Override
                public boolean handleMessage(@NonNull Message message) {
                    return false;
                }
            });
    
    handler3.sendMessage(Message.obtain());
    

    (3)子线程中使用Handler

    上面的Handler都是在主线程中创建的,子线程Handler使用方式如下:

    class LooperThread extends Thread {
        public Handler mHandler;
    
        public void run() {
            Looper.prepare();
            // Step 1: 创建Handler
            mHandler = new Handler() {
                public void handleMessage(Message msg) {
                    //处理即将发送过来的消息
                    System.out.println("thread id="+Thread.currentThread().getId());
                }
            };
    
            Looper.loop();
        }
    }
    
    // Step 2: 创建并启动LooperThread线程,内部包含Looper
    LooperThread looperThread = new LooperThread("gityuan.com");
    looperThread.start();
    
    // Step 3: 发送消息
    LooperThread.mHandler.sendEmptyMessage(10);
    

    可以看到子线程中创建Handler时应先调用Looper的prepare方法,其实主线程中创建Handler也是需要调用prepare方法的,只是主线程在初始化时已经调用过了,所以可以省略。

    另外:
    上面子线程中使用handlerd的方式我们可以直接使用系统提供好的HandlerThread类,Handler创建时传入HandlerThread类的Looper,则handler发送的消息会在HandlerThread中执行。

    2 Handler原理分析

    2.1Handler的创建

    如下图 Hander 对外开放了4种构造参数,有两种已经被废弃。


    image.png
        /**
         * Default constructor associates this handler with the {@link Looper} for the
         * current thread.
         *
         * If this thread does not have a looper, this handler won't be able to receive messages
         * so an exception is thrown.
         */
        public Handler() {
            this(null, false);
        }
    
        /**
         * Constructor associates this handler with the {@link Looper} for the
         * current thread and takes a callback interface in which you can handle
         * messages.
         *
         * If this thread does not have a looper, this handler won't be able to receive messages
         * so an exception is thrown.
         *
         * @param callback The callback interface in which to handle messages, or null.
         */
        public Handler(Callback callback) {
            this(callback, false);
        }
    
        /**
         * Use the provided {@link Looper} instead of the default one.
         *
         * @param looper The looper, must not be null.
         */
        public Handler(Looper looper) {
            this(looper, null, false);
        }
    
        /**
         * Use the provided {@link Looper} instead of the default one and take a callback
         * interface in which to handle messages.
         *
         * @param looper The looper, must not be null.
         * @param callback The callback interface in which to handle messages, or null.
         */
        public Handler(Looper looper, Callback callback) {
            this(looper, callback, false);
        }
    

    第一个和第二个构造函数没有传入Looper对象,调用的是@hide标记的隐藏的构造函数

     /**
         * Use the {@link Looper} for the current thread with the specified callback interface
         * and set whether the handler should be asynchronous.
         *
         * Handlers are synchronous by default unless this constructor is used to make
         * one that is strictly asynchronous.
         *
         * Asynchronous messages represent interrupts or events that do not require global ordering
         * with respect to synchronous messages.  Asynchronous messages are not subject to
         * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
         *
         * @param callback The callback interface in which to handle messages, or null.
         * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
         * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
         *
         * @hide
         */
        public Handler(Callback callback, boolean async) {
            if (FIND_POTENTIAL_LEAKS) {
                final Class<? extends Handler> klass = getClass();
                if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                        (klass.getModifiers() & Modifier.STATIC) == 0) {
                    Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                        klass.getCanonicalName());
                }
            }
    
            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;
        }
    
    

    FIND_POTENTIAL_LEAKS是全局的一个静态变量 注释解释:设置此标志为true以检测扩展此Handler类且非静态的匿名、本地或成员类。这类类可能会产生泄漏。
    构造函数中我们可以看到Handler中的几个全局变量被赋值的操作:

            mLooper = Looper.myLooper();
            mQueue = mLooper.mQueue;
            mCallback = callback;
      
    

    下面是通过Looper的静态方法来获取Looper实例,mLooper = Looper.myLooper();

    看下Looper中这个方法的实现,代码如下:

        /**
         * Return the Looper object associated with the current thread.  Returns
         * null if the calling thread is not associated with a Looper.
         */
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    
        // sThreadLocal.get() will return null unless you've called prepare().
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    

    sThreadLocal 上有一个注释意思是除非调用了prepare()方法否则就返回null。其实就是使用handler之前要先调用Looper的prepare方法创建Looper对象并保存在ThreadLocal中。

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

    如果sThreadLocal中有Looper对象则抛异常,如果没有则调用set方法sThreadLocal.set(new Looper(quitAllowed))

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

    再Looper的这个私有的构造函数中创建了一个MessageQueue 和对mThread进行了赋值。那么队列就是在Looper创建时创建的。

    下面看下这个ThreadLocal这个类

        /**
         * Sets the current thread's copy of this thread-local variable
         * to the specified value.  Most subclasses will have no need to
         * override this method, relying solely on the {@link #initialValue}
         * method to set the values of thread-locals.
         *
         * @param value the value to be stored in the current thread's copy of
         *        this thread-local.
         */
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    
    

    获取当前线程然后获取当前线程的ThreadLocal.ThreadLocalMap threadLocals 变量,map里存储着Looper中的ThreadLocal对象和Looper对象。下面看下getMap(t)方法

        /**
         * Get the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param  t the current thread
         * @return the map
         */
        ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    

    这个方法直接返回了thread的一个全局变量,这个变量类型是

       /* ThreadLocal values pertaining to this thread. This map is maintained
         * by the ThreadLocal class. */
        //翻译:与此线程相关的ThreadLocal值。这个映射由ThreadLocal类维护
        ThreadLocal.ThreadLocalMap threadLocals = null;
    

    而这个ThreadLocalMap 则是ThreadLocal类的一个静态内部类用来维护线程的ThreadLocal值。

       public void set(T value) {
            //获取当前线程
            Thread t = Thread.currentThread();
            //从当前线程拿到map
            ThreadLocalMap map = getMap(t);
            //如果map不为null则设置key为当前ThreadLocal实列也就是Looper里初始化的那个实例,value为Looper实例
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    

    如果map != null则值存入map中,如果map不存在则创建。

        /**
         * Create the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param t the current thread
         * @param firstValue value for the initial entry of the map
         */
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    

    从上面的set方法可以看出get方法其实就是从map里去取Thread类中的threadLocals 然后根据key取得looper

      /**
         * Return the Looper object associated with the current thread.  Returns
         * null if the calling thread is not associated with a Looper.
         */
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    
      /**
         * Returns the value in the current thread's copy of this
         * thread-local variable.  If the variable has no value for the
         * current thread, it is first initialized to the value returned
         * by an invocation of the {@link #initialValue} method.
         *
         * @return the current thread's value of this thread-local
         */
        public T get() {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
        }
    

    当前线程中调用Looper.prepare会创建looper对象并通过Looper类中的静态全局变量sThreadLocal的set方法保存到当前线程ThreadLocalMap中,下次使用时通过get方法获取。

    Handler的第三个第四个构造函数可以直接传入自己的Looper,比如在子线程中创建Handler时传入Looper.getMainLooper()可以将消息发送到主线程中处理达到切换线程的目的。

    2.2开启消息循环

    Looper.prepare()方法会在当前线程中创建Looper,并在Looper的构造函数中创建保存消息的队列MessageQueue()。开启消息队列的循环处理需要调用Looper.loop()方法:

        public static void loop() {
            //获取looper
            final Looper me = myLooper();
            //为空的话抛出异常 提示需要先调用prepare方法
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }
            //循环将使排队的消息在这一次完成之前执行
            if (me.mInLoop) {
                Slog.w(TAG, "Loop again would have the queued messages be executed"
                        + " before this one completed.");
            }
    
            me.mInLoop = true;
    
            // 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();
    
            // Allow overriding a threshold with a system prop. e.g.
            // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
            final int thresholdOverride =
                    SystemProperties.getInt("log.looper."
                            + Process.myUid() + "."
                            + Thread.currentThread().getName()
                            + ".slow", 0);
    
            me.mSlowDeliveryDetected = false;
            //开启循环
            for (;;) {
                if (!loopOnce(me, ident, thresholdOverride)) {
                    return;
                }
            }
        }
    
        private static boolean loopOnce(final Looper me,
                final long ident, final int thresholdOverride) {
            //队列中获取消息,无消息时会阻塞
            Message msg = me.mQueue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return false;
            }
    
            // 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);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;
    
            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
    
            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;
    
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
    
            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                //分发消息
                msg.target.dispatchMessage(msg);
                if (observer != null) {
                    observer.messageDispatched(token, msg);
                }
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } catch (Exception exception) {
                if (observer != null) {
                    observer.dispatchingThrewException(token, msg, exception);
                }
                throw exception;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (me.mSlowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        me.mSlowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        me.mSlowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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);
            }
    
            msg.recycleUnchecked();
    
            return true;
        }
    
    

    2.3消息发送和获取

    handler发送一个消息最终会添加到MessageQueue的队列中,获取时也是从队列中获取。

       public final boolean sendMessage(@NonNull Message msg) {
            return sendMessageDelayed(msg, 0);
        }
    
    
        public final boolean sendEmptyMessage(int what)
        {
            return sendEmptyMessageDelayed(what, 0);
        }
    
        public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
            Message msg = Message.obtain();
            msg.what = what;
            return sendMessageDelayed(msg, delayMillis);
        }
    
        public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
            Message msg = Message.obtain();
            msg.what = what;
            return sendMessageAtTime(msg, uptimeMillis);
        }
    
    
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
            if (delayMillis < 0) {
                delayMillis = 0;
            }
            return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
        }
    
    

    从上面的发送消息的方法中我们可以看到不管是否是哪个方法最终调用的都是sendMessageAtTime这个方法。sendMessageAtTime方法中调用enqueueMessage方法将消息加入队列。

        public boolean sendMessageAtTime(@NonNull 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(@NonNull MessageQueue queue, @NonNull Message msg,
                long uptimeMillis) {
           //将handler保存到msg的tartget中
            msg.target = this;
            msg.workSourceUid = ThreadLocalWorkSource.getUid();
            //判断是否是异步消息
            if (mAsynchronous) {
                //设置异步消息标记
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    
        boolean enqueueMessage(Message msg, long when) {
          
            if (msg.target == null) {
                throw new IllegalArgumentException("Message must have a target.");
            }
            //加锁
            synchronized (this) {
                //判断消息是否在使用中
                if (msg.isInUse()) {
                    throw new IllegalStateException(msg + " This message is already in use.");
                }
    
                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;
                //当前消息为null则代表队列中无消息要处理
                //when=0说明是刚开机
                //when<p.when 说明当前消息要先比队列中的第一消息先执行
                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.
                   // 将 新消息 插入队列的中间,通常我们不会去唤醒这个事件队列,除非在队列头部有一个拦截器,              并且这个 新消息 是队列中最早的异步消息。
                   // 1. mBlocked // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
                   // 表示next()是否被阻塞在pollOnce()中等待非零超时。
                   // 我们再来看看什么时候mBlocked会被赋值,在next()函数里,有消息会被置false;如果没有消息了并且没有没有idle handlers需要执行,则会置true。
                   // 2. p.target == null
                   // 代表着队列头部有一个拦截器,后文会分析postSyncBarrier()代码。
                   // 3. msg.isAsynchronous()
                   // 新消息是否为异步消息
                    needWake = mBlocked && p.target == null && msg.isAsynchronous();
                    Message prev;
                    //循环遍历直到p==null(队列最后一个消息)或者当前消息比遍历到的消息触发的时间小的
                    for (;;) {
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                            break;
                        }
                         // 如果队列有早于新消息的异步消息,则needWake为false。
                        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.
                // 因为mQuitting是false,所以我们可以认为mPtr != 0。判断是否需要唤醒事件队列,如果要唤醒则调用nativeWake(mPtr)。
                if (needWake) {
                    nativeWake(mPtr);
                }
            }
            return true;
        }
    
    

    上面是发送消息并加入队列等待Looper的loop方法中me.mQueue.next()读取的过程。下面看看取出消息的过程:

        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();
                }
                //根据nextPollTimeoutMillis判断是否要阻塞,等于0时不阻塞立即返回,等于-1阻塞
                //当下个消息到达或者发生nativeWake()才会解除阻塞继续执行
                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代表是屏障消息
                    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.
                        //队列中没有消息,这这超时时间为-1
                        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.
                    //当前消息队列空了,或者第一个消息需要在将来被处理(也许是因为barrier),则执行idle handler回调
                    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.
                // queueIdle如果返回true则保持该idleHandler
                // 如果返回false,则处理完之后remove
                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;
            }
        }
    
    

    2.4同步消息、异步消息、同步屏障

    同步屏障是通过MessageQueue的postSyncBarrier方法插入到消息队列的。

    MessageQueue#postSyncBarrier
     private int postSyncBarrier(long when) {
            synchronized (this) {
                final int token = mNextBarrierToken++;
                //1、屏障消息和普通消息的区别是屏障消息没有tartget。
                final Message msg = Message.obtain();
                msg.markInUse();
                msg.when = when;
                msg.arg1 = token;
    
                Message prev = null;
                Message p = mMessages;
                //2、根据时间顺序将屏障插入到消息链表中适当的位置
                if (when != 0) {
                    while (p != null && p.when <= when) {
                        prev = p;
                        p = p.next;
                    }
                }
                if (prev != null) { // invariant: p == prev.next
                    msg.next = p;
                    prev.next = msg;
                } else {
                    msg.next = p;
                    mMessages = msg;
                }
                //3、返回一个序号,通过这个序号可以撤销屏障
                return token;
            }
        }
    

    postSyncBarrier方法就是用来插入一个屏障到消息队列的,可以看到它很简单,从这个方法我们可以知道如下:

    • 屏障消息和普通消息的区别在于屏障没有tartget,普通消息有target是因为它需要将消息分发给对应的target,而屏障不需要被分发,它就是用来挡住普通消息来保证异步消息优先处理的。
    • 屏障和普通消息一样可以根据时间来插入到消息队列中的适当位置,并且只会挡住它后面的同步消息的分发。
    • postSyncBarrier返回一个int类型的数值,通过这个数值可以撤销屏障。
      插入普通消息会唤醒消息队列,但是插入屏障不会。

    Handler有几个构造方法,可以传入async标志为true,这样构造的Handler发送的消息就是异步消息。不过可以看到,这些构造函数都是hide的。

     /**
          * @hide
          */
        public Handler(boolean async) {}
    
        /**
         * @hide
         */
        public Handler(Callback callback, boolean async) { }
    
        /**
         * @hide
         */
        public Handler(Looper looper, Callback callback, boolean async) {}
    

    当调用handler.sendMessage(msg)发送消息,最终会走到:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);//把消息设置为异步消息
            }
            return queue.enqueueMessage(msg, uptimeMillis);
        }
    

    可以看到如果这个handler的mAsynchronous为true就把消息设置为异步消息,设置异步消息其实也就是设置msg内部的一个标志。而这个mAsynchronous就是构造handler时传入的async。除此之外,还有一个公开的方法:

            Message message=Message.obtain();
            message.setAsynchronous(true);
            handler.sendMessage(message);
    

    移除屏障可以通过MessageQueue的removeSyncBarrier方法:

    //注释已经写的很清楚了,就是通过插入同步屏障时返回的token 来移除屏障
    /**
         * Removes a synchronization barrier.
         *
         * @param token The synchronization barrier token that was returned by
         * {@link #postSyncBarrier}.
         *
         * @throws IllegalStateException if the barrier was not found.
         *
         * @hide
         */
        public void removeSyncBarrier(int token) {
            // Remove a sync barrier token from the queue.
            // If the queue is no longer stalled by a barrier then wake it.
            synchronized (this) {
                Message prev = null;
                Message p = mMessages;
                //找到token对应的屏障
                while (p != null && (p.target != null || p.arg1 != token)) {
                    prev = p;
                    p = p.next;
                }
                final boolean needWake;
                //从消息链表中移除
                if (prev != null) {
                    prev.next = p.next;
                    needWake = false;
                } else {
                    mMessages = p.next;
                    needWake = mMessages == null || mMessages.target != null;
                }
                //回收这个Message到对象池中。
                p.recycleUnchecked();
                // If the loop is quitting then it is already awake.
                // We can assume mPtr != 0 when mQuitting is false.
                if (needWake && !mQuitting) {
                    nativeWake(mPtr);//唤醒消息队列
                }
        }
    

    如果队列中没有屏障异步消息和同步消息都是按照时间顺序来执行,但是加入同步屏障就会使异步消息优先执行,直到屏障被移除同步消息才会执行。

    2.5消息回调的优先级

    如代码所示如果msg中设置了callback,则直接执行handleCallback,如果未设置callback,则判断handler的callback是否为null,不为null则执行handleMessage方法,并根据返回的bool值判断是否执行handler自身的handleMessage方法,如果为null则直接执行Handler的自身的handleMessage方法。

      public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    相关文章

      网友评论

          本文标题:Hander源码分析

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