深入浅出Handler(六) Message的创建

128 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情

一、前言

如果你使用handler创建一个消息使用new Message()进行创建的,那么不妨看下这篇文章吧~

二、Message

Android官方更推荐我们使用这两种方式创建message

Message msg1 = Message.obtain();
Message msg2 = handler.obtainMessage();

2.1 Message.obtain()

先来看下Message.obtain()方法吧

public static Message obtain() {
    //加锁
    synchronized (sPoolSync) {
        //消息回收池不为Null
        if (sPool != null) {
            //获取链表头节点
            Message m = sPool;
            //获取第一个Message
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            //消息回收池长度 - 1
            sPoolSize--;
            //返回此消息
            return m;
        }
    }
    //如果是空链表,就新建Message
    return new Message();
}

从上述代码可以看出,obtain()方法会先判断回收池是否为Null,如果为Null,就会new Message().

如果不为Null,就从回收池获取一个旧的Message,然后将msg的flags置为0,返回该消息.

sPool是这个复用的核心.

2.2 handler.obtainMessage()

public final Message obtainMessage()
{
    return Message.obtain(this);
}

handler这里最终还是调用Message内部的obtain(handler)

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
}

2.3 message.recycle()

我们来找一下sPool的复用逻辑吧

public void recycle() {
    //是否正在被使用
    if (isInUse()) {
        //是否能够回收消息
        if (gCheckRecycle) {
            //抛出异常,消息正在被消费,不能够被回收
            throw new IllegalStateException("This message cannot be recycled because it "
                    + "is still in use.");
        }
        return;
    }
    //消息已经被消费过了,可以被回收了
    recycleUnchecked();
}


void recycleUnchecked() {
    
    //将Message回复到初始状态,
    //flags置为FLAG_IN_USE,不能重复入队
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = UID_NONE;
    workSourceUid = UID_NONE;
    when = 0;
    target = null;
    callback = null;
    data = null;

    //将消息添加到回收池,可见这个回收池也是一个链表
    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

至此咱们Handler系列的源码解读即将走向终结,正好把几个核心的源码再读一遍吧~

2.4 Message 成员变量

//用于标记传递执行什么操作,通过用于用户逻辑判断
public int what;

//如果传递数据是整数类型就可以使用arg1和arg2变量
public int arg1;
public int arg2;

//在进程间通信时,传递数据时需要实现Android方式的序列化
public Object obj;

//在进程间通信时,可以通过replyTo给服务端传递一个客户端的Messager的对象,
//此时服务端就可以使用Messager发送消息给客户端
public Messenger replyTo;


public static final int UID_NONE = -1;


public int sendingUid = UID_NONE;


public int workSourceUid = UID_NONE;


/*package*/ static final int FLAG_IN_USE = 1 << 0;

/** If set message is asynchronous */
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

/** Flags to clear in the copyFrom method */
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;

//标记位,标记Message是否正在被使用
/*package*/ int flags;


//消息什么时候被执行
public long when;

//传递数据,封装成Bundle对象
/*package*/ Bundle data;

//新建此消息的handler对象
/*package*/ Handler target;

//handler.postMessage的runnable对象
/*package*/ Runnable callback;

// sometimes we store linked lists of these things
@UnsupportedAppUsage
/*package*/ Message next;

public static final Object sPoolSync = new Object();
//回收的消息池
private static Message sPool;
//回收消息池此时的长度
private static int sPoolSize = 0;
//回收消息池的最大长度
private static final int MAX_POOL_SIZE = 50;
//消息是否能够被回收
private static boolean gCheckRecycle = true;
  • 从上面可以看出,在平常创建Message时,我们一般使用的when,target,obj这些变量.

  • flags这个变量作为标志位,标记此时Message的状态,FLAG_IN_USE表示此时正在被使用

  • sPool是一个单向链表,内部存储着回收消息

2.5 总结

Message就是消息传递的介质,内部的重点就是flags标记状态,sPool是消息回收池,target绑定了handler对象.

三、MessageQueue

MessageQueue是存储消息的一个队列

3.1 构造方法

MessageQueue(boolean quitAllowed) {
    //队列是否能够退出
    mQuitAllowed = quitAllowed;
    //native的MessageQueue引用
    mPtr = nativeInit();
}

3.2 初始化

可以看到MessageQueue的构造方法并没有被开放出来

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

在Looper的构造方法中被实例化,所以Looper是和MessageQueue绑定的,只要创建一个Looper就会创建一个MessageQueue

3.3 MessageQueue成员变量

private static final String TAG = "MessageQueue";
private static final boolean DEBUG = false;

// 是否能够退出
@UnsupportedAppUsage
private final boolean mQuitAllowed;

@UnsupportedAppUsage
@SuppressWarnings("unused")
private long mPtr; // used by native code

@UnsupportedAppUsage
Message mMessages;//链表的头节点
@UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuitting;

// 是否阻塞
private boolean mBlocked;

// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
@UnsupportedAppUsage
private int mNextBarrierToken;

private native static long nativeInit();
private native static void nativeDestroy(long ptr);
@UnsupportedAppUsage
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
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);

3.4 enqueueMessage消息入队

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        //判断消息是否持有发送消息的handler对象
        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;
        if (p == null || when == 0 || when < p.when) {
            // 如果阻塞,唤醒事件队列
            //消息直接入队
            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;
}

可以看到,消息入队前会判断

  • 1、消息是否持有发送消息的handler
  • 2、消息是否正在被使用
  • 3、消息队列是否退出了,如果退出了,那么回收消息

3.5 next消息出队

@UnsupportedAppUsage
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管道连接,等待到手消费消息
            Binder.flushPendingCommands();
        }

        //Epoll机制的阻塞式等待
        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
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                //判断消息是否为null并且是否拥有发送消息的handler
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
            //消息不为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.
                //没有消息可以执行了
                nextPollTimeoutMillis = -1;
            }

            //现在处理退出消息,处理所有挂起的消息
            //消息队列是否需要退出,处理所有的消息,或消费或回收
            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                //调用的底层C代码,处理还没处理的消息
                //准备退出队列了,此方法是安全的退出方式,
                //默认也是安全的退出
                dispose();
                //返回null,looper退出的判断条件
                return null;
            }

           //接下来的就是处理将要执行的消息了
            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;
    }
}

可以看出消息出队的基本步骤

  • 1、消息队列是否已经退出
  • 2、如果没有退出,进入死循环,遍历链表,从链表中取出一个消息,如果消息是Null,就表明没有消息可以处理了
  • 3、如果Msg不为Null,判断消息是否可以立即执行,不过不可以,计算将要执行的时间点
  • 4、如果消息可以立即执行,接下来进行链表的删除操作

可以看到消息的入队和出队操作,其实是在MessageQueue内部维护了一个消息链表,本质上是链表的插入和删除操作.

3.6 quit退出

void quit(boolean safe) {
    if (!mQuitAllowed) {
        //队列是否允许退出,在构造队列时传入
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {
            //队列已经退出
            return;
        }
        mQuitting = true;

        if (safe) {
            //是否安全地退出
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }

        // We can assume mPtr != 0 because mQuitting was previously false.
        nativeWake(mPtr);
    }
}

3.7 removeAllFutureMessagesLocked()

private void removeAllFutureMessagesLocked() {
    final long now = SystemClock.uptimeMillis();
    Message p = mMessages;
    if (p != null) {
        if (p.when > now) {
            //如果链表头节点是延迟消息,那么直接回收掉所有的消息
            removeAllMessagesLocked();
        } else {
            Message n;
            for (;;) {
                n = p.next;
                if (n == null) {
                //如果消息链表是Null,返回
                    return;
                }
                if (n.when > now) {
                //找出链表中的第一个延迟消息
                    break;
                }
                p = n;
            }
            p.next = null;
            do {
                //循环删除第一个延迟消息的所有
                p = n;
                n = p.next;
                p.recycleUnchecked();
            } while (n != null);
        }
    }
}

3.8 removeAllMessagesLocked

private void removeAllMessagesLocked() {
    Message p = mMessages;
   //删除所有的消息
    while (p != null) {
        Message n = p.next;
        p.recycleUnchecked();
        p = n;
    }
    mMessages = null;
}

可以看到

  • 不安全的退出:删除所有的消息
  • 安全地退出:删除第一个延迟消息之后的所有消息(包括第一个延迟消息)

四、Looper

4.1 Looper成员变量

//存储不同线程的数据,使用ThreadLocal实现数据隔离
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//UI主线程关联的mainLooper
@UnsupportedAppUsage
private static Looper sMainLooper;  // guarded by Looper.class
private static Observer sObserver;
//关联的消息队列
@UnsupportedAppUsage
final MessageQueue mQueue;
//该Looper对应的线程
final Thread mThread;
private boolean mInLoop;

@UnsupportedAppUsage
private Printer mLogging;

从成员变量中可以看出

  • Looper已经关联了当前线程的MessageQueue,并且创建了当前线程对象,同时自带主线程的Looper

  • 使用了ThreadLocal来实现线程间的数据隔离

4.2 Looper的创建

public static void prepare() {
    //是否能够出队列
    prepare(true);
}

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
    //当前线程下是否已经存储过Looper对象
    //如果已经存在,抛出异常
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //新建Looper对象,并且将该线程的Looper对象存储到ThreadLocal中
    sThreadLocal.set(new Looper(quitAllowed));
}


@Deprecated
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}


private Looper(boolean quitAllowed) {
    //新建MessageQueue
    mQueue = new MessageQueue(quitAllowed);
    //持有当前线程的线程对象
    mThread = Thread.currentThread();
}

创建Looper主要有这几个步骤

  • 1、创建当前线程的MessageQueue
  • 2、将Looper对象添加到ThreadLocal中
  • 3、持有当前Looper的线程对象

另外值得注意的是,一个线程只允许存在一个Looper,否则会抛异常

4.3 Looper.loop()

public static void loop() {
   //返回当前线程关联的looper对象
   final Looper me = myLooper();
   if (me == null) {
   //表明当前线程不存在looper,没有实例化looper
       throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
   }
   ...
   //死循环
   for (;;) {
       if (!loopOnce(me, ident, thresholdOverride)) {
           return;
       }
   }
}


private static boolean loopOnce(final Looper me,
       final long ident, final int thresholdOverride) {
   //获取当前线程中Looper对象对应的MessageQueue对象
   //从MessageQueue中取出消息,有就取出消息,没有消息,就阻塞
   Message msg = me.mQueue.next(); // might block
   if (msg == null) {
       // No message indicates that the message queue is quitting.
       //消息是否为Null,消息队列退出之后会返回null
       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 {
       //回调给发送这个消息的handler处理
       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;
}

从上述代码可以看出,loop方法内部其实是个死循环,通过轮询MessageQueue的next()方法获取消息,有消息就处理,没有消息时就阻塞等待.

4.4 跳出循环

if (msg == null) {
    // No message indicates that the message queue is quitting.
    return false;
}

当msg为null时这个循环才可以跳出

什么时候在Looper轮询时MessageQueue的next()方法返回null呢

// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
    dispose();
    return null;
}

mQuitting为true时会返回null

void quit(boolean safe) {
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {
            return;
        }
        mQuitting = true;

        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }

        // We can assume mPtr != 0 because mQuitting was previously false.
        nativeWake(mPtr);
    }
}

messageQueue调用quit时会结束looper的轮询

4.5 Looper的退出

public void quit() {
    mQueue.quit(false);
}


public void quitSafely() {
    mQueue.quit(true);
}

从上面可以看出,MessageQueue的quit(safe)方法是在looper中调用的.

  • 不安全退出:直接将所有的消息回收掉
  • 安全退出:退出之前,会先将所有可以立即处理的消息发送给相应的handler处理,然后再回收掉,但是延迟消息是会被直接回收

五、Handler

5.1 成员变量

//当前线程的looper
@UnsupportedAppUsage
final Looper mLooper;
//消息队列
final MessageQueue mQueue;
@UnsupportedAppUsage
//回调,构造函数的参数
final Callback mCallback;
//消息是否是异步的
final boolean mAsynchronous;
@UnsupportedAppUsage
//跨进程间通信时使用
IMessenger mMessenger;

可以看到,handler持有Looper对象和MessageQueue

5.2 handler的创建

@Deprecated
public Handler() {
    this(null, false);
}


public Handler(@Nullable 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) {
    //判断当前线程的looper对象是否为Null
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    //获取MessageQueue
    mQueue = mLooper.mQueue;
    //callback回调
    mCallback = callback;
    //是否异步
    mAsynchronous = async;
}


@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

可以看到,handler有两种创建方式

  • 1、直接创建handler,new Hander()
  • 2、创建handler,并实现callback接口

在handler的构造函数中我们也可以看到mQueue和mLooper都是直接获取的,所以必须先创建Looper,再创建handler

5.3 handler发送消息

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

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


public final boolean sendMessage(@NonNull Message msg) {
    return sendMessageDelayed(msg, 0);
}


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

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

其实最终都是sendMessageDelayed的调用. 因为需要计算这个消息需要延迟执行的时间

  • post():参数实现callback的接口类,在Runnable的run()方法中处理消息
  • sendMessage():复写handleMessage()方法

5.4 接收消息

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        //实现的Runnable接口是否为Null,如果不是null,就执行
        //handleCallback方法
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //判断mCallback是否为Null
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //以上判断都不成立,handleMessage方法
        handleMessage(msg);
    }
}
  • 首先是否实现了Runnable接口,如果已实现,回调给run()方法,就此结束,不再走步骤2,否则步骤2
  • 是否实现了Callback接口,如果实现了,回调给callBack内的handleMessage方法,此时handleMessage返回true,就结束,不再走步骤3,否则步骤3
  • new Handler(handleMessage(msg))内的方法执行

六、总结

至此,我们再来总结一下handler的使用方法和流程

  • 1、实例化handler之前必须确保Looper.prepare()已经被调用
  • 2、确保looper和messageQueue已经创建
  • 3、handler通过sendXXX或者postXXX发送消息
  • 4、发送消息的本质就是调用MessageQueue的enqueuMessage方法(消息入队列)
  • 5、Looper的loop,进行消息的轮询,其实是阻塞式地拿到MessageQueue.next()消息
  • 6、Looper取到消息后根据msg.target将消息分发给关联的handler
  • 7、handler内部处理消息通过dispatchMessage(Msg),回调给开发者