Android消息机制-Handler再学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/One_Month/article/details/81745326

Handler消息机制,主要由4个类构成
1.Handler 发送和处理消息
2.Message 消息的载体
3.MessageQueue 存储消息的队列,实际他更像是单链表
4.Looper 消息循环,主要是取出MessageQueue中的Message进行分发

几者之间的关系如图
这里写图片描述
下文就按照执行的流程,分析一下执行过程中具体的步骤和执行的操作

1.Looper

可以先看一下Looper的构造器

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

可以看到Looper的构造器内部会自动创建MessageQueue对象,所以可以说Looper
和MessageQueue是绑定创建的。

在子线程创建Looper一般不是直接通过构造器,而是调用静态方法Looper.prepare(),
一起看下

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

可以看到,新建的Looper保存到了sThreadLocal中,这个是一个ThreadLocal对象可以
在不同线程中保存同一变量的不同副本,使线程之间相同变量保持独立。

2.Handler

先来看下他的构造器
    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());
            }
        }
        //调用静态方法,取出当前线程的Looper对象,其实就是取出ThreadLocal
        //中保存的之前创建的Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //取出looper中创建的MessageQueue,这个Handler发送的Message都会添加
        //到这个MessageQueue中,由于同一个线程取出的MessageQueue是相同的
        //所以同一个线程的多个Handler对应同一个MessageQueue,即Handler与
        //MessageQueue可以为 多对一关系
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

再看一下Handler的一个功能,发送消息。发送消息可以调用sendXXX或者post,最终来到sendMessageDelayed()

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

又转到sendMessageAtTime

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

通过传入的参数可以看出来,发送的消息其实是按照一定时间顺序最终插入队列,最终调用enqueueMessage入队。

入队后就是MessageQueue的入队操作,接下来就与MessageQueue相关了

3.MessageQueue

接着上面的操作,看下enqueueMessage过程

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.");
        }
        //上面检测Message的合法性
        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;
            //这玩意相当这个链表的头结点(MessageQueue的操作实际是一个单链
            //表操作)
            Message p = mMessages;
            boolean needWake;
            //如果头结点为null或者添加的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.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                //如果不符合条件,就继续遍历,看新加的Message的时间when
                //在哪两个Message之间,然后做插入操作
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //两个结点之间插入这个Message
                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;
    }

看了添加,我们看下怎么取出,取出用到了MessageQueue的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();
            }

            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());
                }
                //找到第一个非同步屏蔽的Message
                if (msg != null) {
                    //还没到message该处理的时间
                    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;
                        //取出目标节点,重新设置结点的next引用
                        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;
                }
    //省略部分代码
 }
    }

可以看到还是单链表的删除操作,如果找不到目标Message,这里会一直循环,阻塞在这个地方

当然,next方法不会自己启动,调用它的就是Looper,在Looper的loop方法中调用了它

 /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the 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.");
        }
        //取出Looper中的MessageQueue对象
        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 (;;) {
            //在这里调用MessageQueue的next方法,取出下一个Message
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

           //省略部分代码
            try {
                //msg.target就是发送这个Message的Handler,调用它的
                //dispatchMessage()来处理消息,因为这个方法在这里
                //被调用,所以handler处理消息的过程就会跑到当
                //前的线程中,也就是Looper的创建线程
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            //省略部分代码
            msg.recycleUnchecked();
        }
    }

由于loop方法在执行死循环,所以如果在子线程创建了消息队列,不再使用时最好调用
Looper的quit()直接退出循环,或者quitSafely等待消息处理完退出。

猜你喜欢

转载自blog.csdn.net/One_Month/article/details/81745326