Android 消息机制

Android 是基于事件机制的,每一次触摸事件或者生命周期都是运行在 Looper.loop()的控制之下的,所以理解 Android 的消息机制能使我们更好的进行开发。
Android 的消息机制主要是指 Handler 的运行机制,主要的作用就是在不同的线程之间进行通信。我们在一般的开发中,主要是用来在子线程中进行耗时操作,然后当需要更新 UI 时,通过 Handler 将需要更新 UI 的操作切换到主线程中去做。其实不积极是主线程和子线程可以通过 Handler 机制进行通信,各个子线程之间也可以通过 Handler 进制进行通信。
Handler 机制主要包括这几个部分:Message、Handler、Loop、MessageQueue、ThreadLocal
Message
Message 是在线程之间进行传递的消息,它可以携带少量的信息,用于在不同的线程之间进行数据交换。可以用 whart、arg1、arg2字段携带一些简单的整型数据,可以通过 obj字段携带一个 Object 对象。

MessageQueue
MessageQueue是消息队列。MessageQueue 用一个单链表的数据结构存储通过 Handler 发送过来的Message,然后根据消息的触发时间排序。

Handler
用于处理和发送消息(Message)的。发送消息一般是在Looper 线程(例如主线程)中构造一个Handler,然后在其它线程中调用 Handler 中调用 sendMessage 等方法,此时在Looper 线程中的 MessageQueue 中会插入一条 Message等待被轮询执行。Handler 在被创建的时候会通过 ThreadLocal来获取当前线程的 Looper来构造本线程的消息循环系统。

Looper
Looper 扮演的是在 MessageQueue 和 Handler 之间一个桥梁的作用。Looper 在创建的时候会创建一个 MessageQueue。当我们调用 Looper.loop()方法时开始消息循环(一个死循环),不断调用 MessageQueue 的 next()方法,当 MessageQueue 中有消息时,就传递到对应的 Handler 的 handlerMessage 中去处理,否则阻塞在 next()方法中,当 Looper 的 quit()方法被调用时会调用 MessageQueue 的 quit()方法,此时 next()方法会返回一个 null,然后 loop()也会跟着退出。每个 Looper 线程只有一个 Looper 对象。

ThreadLocal
ThreadLocal是线程内部的一个数据存储类,通过它可以在指定的线程中存储数据,并且只有该线程才能获取到这个数据,其它线程是无法获取到这个数据的。要使用Handler就必须为线程创建Looper,而Looper 的作用域是当前线程,并且每个线程的 Looper 是不同的,那么用 ThreadLocal 来进行存储就非常方便了。

下面附上一张从网上摘抄的 Android 的Handler 的处理流程,如果侵权了麻烦通知本人删除
消息机制

具体分析

在分析 Android Handler 机制之前,为了更好的理解 Looper的工作原理,我们先来简单看下 ThreadLocal 的相关知识。

ThreadLocal 原理

ThreadLocal 主要是通过get 和 set 来进行数据的存取的,搞懂了这两个方法基本上也就了解了 ThreadLocal的原理了。
首先我们进入 ThreadLocal 的get 方法的源码看下:
get
在 get 方法中我们看到 ThreadLocal 通过一个 ThreadLocalMap 来存储数据的。这个 ThreadLocalMap 是Thread 里面的一个类。我们到 getMap 这个方法中去看一下
在这里插入图片描述
可以看到这个 ThreadLocalMap 是 Thread 中的变量。我们先看下 ThreadLocalMap的构造函数
在这里插入图片描述
我们看到 ThreadLocalMap 中通过一个 Entry[] table 变量来存储数据。
在这里插入图片描述
从 Entry 源码中我们可以看到,Entry结构实际上继承了一个ThreadLocal 类型的若引用,并将其作为 key,value 为 Object 类型。
从上面我们可以得到一个简单的结论:
每个 Thread 在其生命周期中都会维护一个 ThreadLocalMap,当 ThreadLocal存储数据时,会从当前线程中获取到其维护的 ThreadLocalMap,然后将当前 ThreadLocal作为 key 将数据存到 ThreadLocalMap 中去。取数据就是以当前的 ThreadLocal 为 key 去当前线程维护的 ThreadLocalMap 中去取 value。
我们看下 set/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
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            //以当前的 ThreadLocal 为 key 获取 map 中的 Entry
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;//得到 value
                return result;
            }
        }
        return setInitialValue();
    }

    /**
     * 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)
            //设置 value
            map.set(this, value);
        else
            createMap(t, value);
    }

这里不对 ThreadLocal 做深入探讨,以后有机会另开一篇博文进行探讨。

MessageQueue 工作原理

MessageQueue 是消息队列,主要有两个功能插入和读取
从Handler源码可以看出
在这里插入图片描述
在这里插入图片描述
插入主要对应的是 enqueueMessage 方法,读取主要是走的 next()方法,每读取一个消息就会删除这个消息。
我们先看下 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.");
        }

        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.
                //当队列为空或者即将要插入队列的message 需要立即执行,或者执行时间早于
               //当前队列的第一个消息,则把该消息设置为第一个要处理的消息。
                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;
                for (;;) {
                    prev = p;
                    p = p.next;
                    //找到一个Message,when小于该message的when break
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
                //这个 else 其实就是将 Message 根据msg的开始执行时间进行先后执行顺序的排序
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

简单说下这个过程:
首先当有一个消息过来需要插入 MessageQueue 中的时候,首先判断该消息是否绑定了 Handler(target)对象或者该 Message 是否正在使用中,接着判断MessageQueue 是否正在退出。如果前面几种情况都没有发生,则将当前信息设置为正在使用,同时进行一些配置。接下来是判断当前的这个 Message 应该插到 MessageQueue 队列中的什么位置。
**if (p == null || when == 0 || when < p.when)**首先是这句。要搞懂这个判断就要搞懂这个 when 是什么玩意儿。在 Handler 中我们看到这个 when 是通过sendMessageAtTime(Message msg, long uptimeMillis)方法的uptimeMillis参数传进来的,当我们用 send(Empty)Message或者send(Empty)MessageDelayed方法发送消息的时候这个when 是uptimeMillis+delayed(send(Empty)Message的 delayed 值为0) 值。而当我们调用sendMessageAtTime(Message msg, long uptimeMillis)时这个 when 就是我们设置的uptimeMillis。也就是说如果我们在所有发送消息的时候将sendMessageAtTime的uptimeMillis设置成0的时候,那么这些消息的执行顺序可能是不确定的)。下面我们用一个例子来简单验证下。

    private Handler handler =  new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.e("AppCompatActivity", "msg " + msg.arg1);
            for (int i = 0; i < 10000; i++) {

            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler1);
        new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                Message msg = handler.obtainMessage();
                msg.arg1 = i;
                handler.sendMessageAtTime(msg, 0);
            }
        }).start();

    }

在这里插入图片描述
通过这个运行结果我们可以看出,消息的执行顺序是不确定的(因为新插入的消息始终是插在队列的最前面,这时候哪些消息已经处理了,可能是不确定的)。当然这不是唯一结果,每次运行的结果可能都不一样。那么在我们用sendMessageAtTime的时候就要注意了。

接下来我们来看下 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;//mPrt是native层的MessageQueue的指针
        if (ptr == 0) {//当消息循环已经退出,则直接返回 null
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

			//阻塞操作,其中nextPollTimeoutMillis超时返回时间,当超时时间到或者被唤醒都会返回
			//nextPollTimeoutMillis=-1表示一直等待,0表示立即返回。
            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) {
                	//当消息为空或者消息没有 Handler 则查找 MessageQueue 中下一条异步消息来处理
                	//为空则退出
                    // 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) {
               		 //判断msg 的执行时间是否大于当前时间,也就是说这条消息有没有到执行时间
                    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 {//如果已经到了执行时间,则返回这个 msg。
                        // 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 {//如果msg为空 表示没有消息,设置nextPollTimeoutMillis = -1,等待被唤醒。
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {//如果队列正在退出,则返回 Null
                    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(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;
        }
    }

简单的说,就是 next 根据消息的触发时间来获取下一条需要处理的消息,如果没有消息,则进行阻塞操作。当消息队列退出或者正在退出状态,则返回 Null。

Looper工作原理

Looper 在消息机制中被用作将线程一个普通线程变成 Looper 线程,所谓Looper 线程就是能够执行循环取消息的工作的线程。Looper 会不停的从 MessageQueue 中查看是否有新的消息,如果有消息,就立即处理。如果没有消息就阻塞。在 Looper 的构造函数中会创建一个 MessageQueue,并保存当前线程的对象。

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

从这个构造函数可以看出Looper 是无法在其它类直接通过 new Looper 创建的。

1、Looper 的创建
我们要想创建 Looper 可以通过Looper.prepare这个静态方法进行创建。

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

这个方法首先判断当前线程是不是已经创建过 Looper 了 如果已经有了 Looper 了,则会报错,因为一个线程只能拥有一个 Looper(这里是通过 ThreadLocal 来保存当前线程的Looper)。然后再通过上面我们说的构造函数进行进行 Looper 的创建。

2、Looper.loop()
调用 Looper.loop 方法后,该线程将开启消息循环。该方法是一个阻塞性的死循环,它会一直循环自己的MessageQueue,并从中取出对头消息进行处理。

    /**
     * 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();//得到当前线程Looper
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//得到Looper的 MessageQueue

        // 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 msg = queue.next(); // might block
            if (msg == null) {
            	//当 next 返回 null,说明队列已经退出了。则跳出循环
            	//所以当我们自己在将普通线程变成 Looper 线程后在不需要这个线程继续处理消息时记得退出
                // 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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
            	//调用 msg 的Handler 进行消息分发。
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            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对象的时候,只是清空Message里面的内容,并且添加到sPool中去,以便下次复用
            msg.recycleUnchecked();
        }
    }

其实简单来说,调用 Looper.loop()方法后,将不断重复以下的操作:
读取 MessageQueue 中的下一条Message,然后把消息分发给对应的 Handler 来处理。如果当前的 MessageQueue 中没有消息则进入阻塞状态,等待有消息进入队列时进行唤醒。
当调用 Looper 的 quit 或者 quitSafely 方法后,Looper 会调用 MessageQueue 的 quit 方法是队列退出循环,从而 Looper也会退出循环(通过上面的MessageQueue 的 next 方法我们知道 next 方法返回 null 是退出循环的唯一方式)。
quit 方法是直接退出 Looper,quitSafely是先设定一个标志,等所有消息处理完毕之后再退出。

Handler 工作原理
Handler 在消息机制中扮演的是往 MessageQueue 中添加Message 以及处理 Message 的角色(Handler 只处理自己发出的消息)。也就想当于 Handler 给自己发了条消息,只是消息经过了消息队列以及Looper,最后才到自己的 handleMessage 方法里面,而这个过程是异步的。
Handler 在创建时会关联一个 Looper,默认情况下是关联当前线程的,而如果此时当前线程还不是 Looper 线程的话就会报错。当然你也可以通过构造函数在创建的时候指定一个 Looper。而我们前面说的 Looper 会创建一个 MessageQueue,同时关联当前的线程。那么到这里 Handler 、Looper、MessageQueue 以及 Thread 就整个关联起来了。

1、Handler 的创建
接下来我们来看下 Handler 的构造函数。主要看下面两个构造函数:

/**
     * 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());
            }
        }
		//默认为当前线程的 Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;//关联MessageQueue
        mCallback = callback;//handlMessage 回调
        mAsynchronous = async;
    }
    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also 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 looper The looper, must not be null.
     * @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(Looper looper, Callback callback, boolean async) {
        mLooper = looper;//关联 Looper
        mQueue = looper.mQueue;//关联 MessageQueue
        mCallback = callback;//handleMessage 回调
        mAsynchronous = async;
    }

这里有个mAsynchronous参数,这个为 true 表示 Handler 是异步的,那么发出的消息就是异步的。在这里我们暂时不讨论这个参数的具体意思。
2、发送消息
** 1)、send 方式**
send 方式最终都会走到 sendMessageAtTime(Message msg, long uptimeMillis)方法。

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;//先判断是否有 MessageQueue
        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方法
    }

接下来再看下enqueueMessage方法:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//将Message 的 target 设置成当前的 Handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //调用 MessageQueue 的 enqueueMessage 方法上面已经介绍过了。
        return queue.enqueueMessage(msg, uptimeMillis);
    }

2、post 方法
post方法最终其实也是走到 sendMessageAtTime方法中,但是又有所区别:

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

        private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }

我们可以看到 post 方法总是要传一个 Runnable的参数,通过 getPostMessage 方法我们可以看到,post 首先创建一个 Message,然后设置 Message 的 callback 为 Runnable,如果有 Object 数据的话设置 Message 的 obj 为要传递的数据。
注意:我们看到 Handler 在构建 Message 的时候用的是 Message.obtain() 而不是直接 new 一个 Message
我们先来看下obtain 方法:

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
               //将表头 Message 移除作为重用的 Message 对象
               //同时将表头的下个节点当做新的表头
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    /*package*/ Message next;

    private static final Object sPoolSync = new Object();
    private static Message sPool;
    private static int sPoolSize = 0;

我们从这几个参数入手,来看下这么做的理由:
1、sPoolSync:这个参数用来给 Message 加个所,不允许多个线程同时访问。
2、sPool:存储循环利用的 Message 链表,注意这个 sPool 只是链表的头结点。
3、sPoolSize:存储列表的长度,即当前可循环利用的 Message 个数。
而且我们可以看到这些参数都是静态变量,也就是说这些 Message 是整个应用共享的。
以上就是 Message.obtain的原理。通过 obtain 方法获取可重用的 Message,减少了每次获取 Message 去初始化申请空间的时间。同时也减少了不停的去新建 Message对象,减少了 JVM 垃圾回收的压力,提高了效率。

3、消息的分发和处理
在之前的讨论中可以看到在Looper.loop()方法中有这么一行代码
msg.target.dispatchMessage(msg);
这个其实是调用 Handler 的dispatchMessage方法:

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {//post 方法发送的消息,或者设置了 callback 的 Message
            handleCallback(msg);
        } else {
            if (mCallback != null) {//如果在创建 Handler 的时候指定了callback,则调用 callback 的handleMessage方法
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //如果在创建的时候没有指定 callback,则调用 Handler 自身的handleMessage方法。
            //我们需要手动去复写该方法,在这个方法中对消息进行处理
            handleMessage(msg);
        }
    }
    private static void handleCallback(Message message) {
        message.callback.run();//调用 callback(Runnable) 的 run 方法
    }

从上面的代码我们也可以看出,Message 的处理优先级是,首先将消息传递给 Message的 callback(Runnable),如果 Message 没有设置 callback,怎判断在初始化 Handler 的时候有没有指定 callback,如果指定了就调用这个 callback 的handleMessage方法,如果前两个都没设置,则调用 Handler自身的 handleMessage方法。
到这里 Android 的消息机制,基本上就介绍完了,最后上几张从网络上摘抄的图片方便更好的理解 Android 的消息机制。(如果有侵权,请联系本人删除)。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值