Handler 源码分析

 

1.概念

    Handler主要用于线程之间的通信,例如刷新主界面UI等,其通信流程图如下:

Handler流程图

在这个过程中,Handler即作为发起者也作为终结者,Message作为基本信息载体,MessageQueue作为消息体的集合,Looper将这三者串联起来。

2.Message

2.1概念 message    

  官方解释: 包含任意类型的对象和描述信息,可以被发送给 Handler。(官方文档:https://developer.android.com/reference/android/os/Message

2.2Message中关键变量

  1.What用于标识Message具体是做什么的

  2.arg1、arg2用于存储简单的整型数据

  3.Bundle用于存储复杂的数据

  4.跨进程通信绑定数据的 object(主要应用在Messenger跨进程通信https://blog.csdn.net/qq_16736297/article/details/85618729

5.与之关联的Handler

6.另外就是一些标志位

具体详细的变量介绍如下:

 /**
     * 用来标识消息身份ID,接收消息方可以根据这个身份ID知道这个消息是做什么的
     */
    public int what;

    /**
     *   如果你的消息要传递的数据是整型的,可以直接使用 arg1 和 arg2,而不需要使用构造一个 Bundle
     */
    public int arg1;
    public int arg2;

    /**
     * 一个任意类型的对象,在使用 Messenger 跨进程传递消息时,通常使用它传递给接收者
     * 在其他场景下我们一般使用 setData() 方法
     * 具体适用场景可以去访问()
     */
    public Object obj;

    /**
     * 负责回复消息的 Messenger,有的场景下(比如接受者、发送者模型)需要使用它
     */
    public Messenger replyTo;


    /**
     * 当前消息的标志,只在被 Messenger 传递消息时使用,其他情况下都是 -1
     */
    public int sendingUid = -1;

    //标识当前消息是否在被使用
    //当一个消息入队时这个标志会被改变,在被重新获取后重置
    //当一个消息已经在被使用时,二次入队或者回收会报错(这就是我前言中提到的错误原因)
    /*package*/static final int FLAG_IN_USE = 1 << 0;

    //标识当前 消息是否是异步的
    /*package*/static final int FLAG_ASYNCHRONOUS = 1 << 1;

    //在 copyFrom 方法中要清除的标志
    /*package*/static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
    /*package*/int flags;

    /*package*/long when;

    //很关键的数据部分
    /*package*/Bundle data;

    //发送和处理消息关联的 Handler
    /*package*/Handler target;

    //消息的回调
    /*package*/Runnable callback;

    //在有些场景下还会以链表的形式关联后一个消息
    /*package*/Message next;

    //消息池
    private 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;

2.3Message的获取方式

  在官方文档中Message中的有如下两种:

    1.Message.obtain();

    2.Handler.obtainMessage();

需要注意的是Message的构造函数是public,但这里并没有去创建,而是选择利用上面的这两种方式从消息池中获取,这样做的原因是为了节省内存。

另外这两种获取方式本质上并没有什么区别,从下面的源码中可得知Handler.obtainMessage()还是调用了Message.obtain()

   /**
     * Returns a new {@link android.os.Message Message} from the global message pool. More 
     *efficient than
     *creating and allocating new instances. The retrieved message has its handler set to 
     *this instance (Message.target == this).
     *If you don't want that facility, just call Message.obtain() instead.
     */
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

2.4Message.obtain()分析

  Message.obtain()在Message中有7个重载方法,此处只分析最复杂的一个,具体源码如下:

 public static Message obtain(Handler h, int what,
            int arg1, int arg2, Object obj) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.arg1 = arg1;
        m.arg2 = arg2;
        m.obj = obj;

        return m;
    }
     /**
      * Return a new Message instance from the global pool. Allows us to
      * avoid allocating new objects in many cases.
      */
    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();
    }

可以看到,这个方法会获取前面提到的 private static Message sPool; ,如果 sPool 存在就从复用消息链表头部取一个消息,然后重置它的标志位;如果不存在复用消息链表就新建一个消息。

既然消息是从消息池中添加,那么问题来了,消息是何时添加的呢?

2.5Message的回收利用

看下面的源码

    void recycleUnchecked() {
        flags = FLAG_IN_USE;//信息标志位flag,当信息被使用时,会被标志为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++;
            }
        }
    }

recycleUnchecked()方法将Messageflag赋值为FLAG_IN_USE,如果此时被标记过的Message再次被放进队列,就会报错this message is already in use。当然此时Message所承载的数据也被清除,然后将其放入消息回收池中,以待下次使用。

那么问题又来了,recycleUnchecked()何时会被调用呢?扒开源码,我们会发现此方法在MessageQueue 和 Looper中都有使用,

MessageQueue.removeMessages()的源码如下:

 void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();//在此处调用
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();//此处有调用
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

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

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

        boolean slowDeliveryDetected = false;

        for (;;) {
            Message msg = queue.next(); // might block
            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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            //此处省略部分代码
            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();//在此处调用了recycleUnchecked()方法;
        }
    }

MessageQueue.removeMessages()Looper.loop()方法中可以看出,此处当消息被移除消息队列时或者被Looper处理以后就会被标识为FLAG_IN_USE,然后被放入消息回收池中,当我们再次使用时,会通过Message.obtain()到消息链表进行获取。

那么问题再次来了,什么是消息回收池,所谓的消息池用于存放还未处理的消息

3.MessageQueue

  MessageQueue是一个管理Message的消息列表,由Handler为其添加Message,由Looper进行取出。

3.1Message的主要关键变量

  // 队列是否可以退出
    private final boolean mQuitAllowed;

    @SuppressWarnings("unused")
    private long mPtr; //底层使用的 code

    //消息链表的开头
    Message mMessages;
    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
    private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
    private IdleHandler[] mPendingIdleHandlers;
    private boolean mQuitting;
    //指出获取下一个消息的方法 next() 是否阻塞
    private boolean mBlocked;

    // Barriers are indicated by messages with a null target whose arg1 field carries the 
       token.
    //后一个屏障的 token 
    private int mNextBarrierToken;

MessageQueue其实类似于LinkList列表,持有消息列表的一个节点

3.2MessageQueue的初始化

MessageQueue是不能直接被访问,而是通过Looper.myQueue()方法进行获取,源码如下:

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

可以从MessageQueue的构造函数中看出,其构造函数传入一个是否中途撤出的标志位,有native层初始化。

当我们获取MessageQueue之后,开始向其添加Message

3.3消息入队的过程

Message入队通过enqueueMessage()方法,让我们来一起扒拉扒拉这个方法的源码:

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {//此处必须给Message设置一个目标,即与他相关联的Handler
            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();//Message入队以后就会被标记为被使用
            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;
    }

在此方法中,有一步检查消息是否被使用,是的话会报错,具体如下:

if (msg.isInUse()) {    
        throw new IllegalStateException(msg + " This message is already in use.");
}

由上可知当我们在Handler.sendMessage()时,必须Message.obtain()或者new Message()对象。当然,如果已退出队列再次添加也会报错。说完消息进队,下面该讲消息如何出队

3.4消息出队

Message的出队是有MessageQueue.next()方法进行,接下来我们开始进行撸码行动

Message next() {
        // 如果消息的Looper退出,就退出这个方法
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        //循环,有消息就返回,没有消息就阻塞
        for (;;) {
           //如果有过段时间在需要要处理的消息,就先调用Binder的这个方法
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // 获取下一个消息
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;//当前链表的头节点
                if (msg != null && msg.target == null) {
                    //如果消息没有 target,那它就是一个屏障,需要一直往后遍历找到第一个异 
                    //步的消息
                      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 (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();//标记这个消息在被使用
                        return msg;
                    }
                } else {
                    // 消息链表里没有可以处理的消息了
                    nextPollTimeoutMillis = -1;
                }

               //如果收到退出的消息,并且所有等待处理的消息都处理完时,调用 Native 方法销毁队列
                if (mQuitting) {
                    dispose();
                    return null;
                }

                //有消息等待过段时间执行时,pendingIdleHandlerCount 增加
                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()方法里有一个循环,循环的目的是找到消息链表中一个可以处理的,target不为空的并且可执行的事件不再未来的消息就返回,否则继续找,当然如果无任何消息或者未来一段时间在处理,这时会将mBlock这个标量置为true,然后在下一个Message判断进队时就会判断这个Message的位置,如果在队首就会调用 nativeWake() 方法唤醒线程!

在有关堵塞的问题上,我们发现MessageQueue.java中有一个IdleHandler,这个方法是干嘛用的呢

public static interface IdleHandler {
        /**
         * 1.消息队列没有消息时,就会调用这方法,阻塞等待消息进入
         * 2.返回true的话表示唤醒堵塞线程,false表示移除
         * 3.如果消息队列中有消息等待在将来执行,也会调用这个方法      
         */
        boolean queueIdle();
    }

根据注释和源码可知,IdleHandler是一个线程阻塞时回调的接口。当然在MessageQueue提供监听阻塞回调的注册和移除接口:

public void addIdleHandler(@NonNull IdleHandler handler) {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        synchronized (this) {
            mIdleHandlers.add(handler);
        }
}

public void removeIdleHandler(@NonNull IdleHandler handler) {
        synchronized (this) {
            mIdleHandlers.remove(handler);
        }
    }

但消息队列被阻塞时,会回调监听阻塞的观察者,告诉他们:“我有空了,赶紧嗨起来!!!”

4.Looper

4.1概念:Looper 是用于运行一个线程中的消息的类。

4.2Looper的关键属性

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;  // 主线程中的 Looepr

final MessageQueue mQueue;    //与之管理的消息队列
final Thread mThread;    //所在的线程

private Printer mLogging;
private long mTraceTag;

4.3线程相关的ThreadLocal

在线程如何通过Looper.prepare()创建一个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));
}

通过上述代码可知,每个线程只有一个Looper,而创建Looper都需要通过ThreadLocal,那ThreadLocal又是何方神圣呢,我们来扒拉扒拉其中主要的源码:

 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();
    }
  
 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

从上面的源码set和get中有一个ThreadLocalMap,这个ThreadLocalMap里持有一个Entry,撸下源码:

 static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

从上面的源码,可以看出ThreadLocal先通过当前线程获取一个ThreadLocalMap,然后在ThreadLocalMap中保存ThreadLocal和数据的关联。ThreadLocalMap类似于Map

4.4无限循环调度

通常在线程创建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) {    //当前线程必须创建 Looper 才可以执行
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

    //底层对 IPC 标识的处理,不用关心 
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {    //无限循环模式
        Message msg = queue.next(); //从消息队列中读取消息,可能会阻塞
        if (msg == null) {    //当消息队列中没有消息时就会返回,不过这只发生在 queue 退出的时候
            return;
        }

        //...
        try {
            msg.target.dispatchMessage(msg);    //调用消息关联的 Handler 处理消息
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        //...
        msg.recycleUnchecked();    //标记这个消息被回收
    }
}

pasted:https://blog.csdn.net/u011240877/article/details/72892321 

由上可知,Looper.loop(),通过MessageQueue.next()取出信息,如果没有消息的话的会阻塞,直到有新的消息进入或者消息队列退出。

当拿到消息后,调用消息相关联的Handler处理。

既然能开启循环那么如何终止循环呢

4.5退出循环

  在源码注释中就提到,当开启循环后,不要忘记调用quit()方法终止循环。

退出循环有两个方法在Looper里,quit和quitSafely的源码

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

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

而两种方式里调用的最终都是MessageQueue.quit(boolean),具体如下:

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);
    }
}
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) {
                    return;
                }
                if (n.when > now) {
                    break;
                }
                p = n;
            }
            p.next = null;
            do {
                p = n;
                n = p.next;
                p.recycleUnchecked();
            } while (n != null);
        }
    }
}
private void removeAllMessagesLocked() {
    Message p = mMessages;
    while (p != null) {    //挨个遍历链表,把消息都回收了
        Message n = p.next;
        p.recycleUnchecked();
        p = n;
    }
    mMessages = null;
}
plaste:https://blog.csdn.net/u011240877/article/details/72892321 

从上述源码可以看出,这两种方式的区别

1.quit():立即把消息链表中的消息都回收掉

a.在停止后,如果Handler还发送消息,就会返回false,入队失败

b.由此也可得出此方法并不安全

2.quitSafely()

a.只会将未执行的消息回收掉

b.在调用之后添加的消息,不会被处理,Handler.sendMessage()也会返回false

当消息队列表标记退出状态时,他的next()方法会返回null,于是Looper.loop()循环就结束了

5.Handler

在介绍完LooperMessageQueueMessage之后,接着该主角登场了,作为最终的发起者和结束者,Handler又是何方神圣呢?

Handler所做的就是切换线程:

a.在子线程中将Message或者Runable发送到发送到消息队列MessageQueue中。

b.然后等待Looper调度这个Message之后,再度召唤Handler来处理。

c.这时消息已经在创建Handler的线程了

接下来我们逐步分析Handler是如何实现线程间的切换的

5.1Handler的关键属性变量

final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;

由上不难发现,Handler属性十分简单,其中Callback可以作为构造函数的参数创建Handler

public Handler(Callback callback) {
    this(callback, false);
}
public interface Callback {
    public boolean handleMessage(Message msg);
}
paste:https://blog.csdn.net/u011240877/article/details/72892321 

平时我们在使用Handler中,一般都是创建Handler的子类,然后重写其handleMessage()方法,现在可以通过Callback()构建Handler,如下:

Handler mHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        //这里处理消息
        return false;
    }
});

paste:https://blog.csdn.net/u011240877/article/details/72892321 

但是这种方式容易造成内存泄露,因为是匿名内部类,持有外部引用。

OK,了解Handler的如何创建之后,那Handler是如何发送信息

5.2发送信息

Handler发送的数据类型有两种:Message和Runnable

发送方式有两种post和send,post发送的是Runnable,而send发送的是Message,但Runnable最终也会转成Message

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

有上述源码可知,我们直接去扒拉sendMessage源码

public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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在发送消息后最终调用了MessageQueue.enqueueMessage()方法。

而我们最常使用的Handler.sendMessagedDelayed()发送延迟消息后,其实在最后入队后指定这个Message的msg.when(),在MessageQueue.next()方法中,会对msg.when>now的消息作出延迟处理,其具体实现在Native层。

当消息入队后,由Looper启动后,循环取出消息,交给target.dispatchMessage(),Handler.dispatchMessage()来处理消息,其具体的源码如下:

/**
 * Handle system messages here.
 */
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();
}
public void handleMessage(Message msg) {
}

有上述源码可知,Handler在处理消息时有三种情况:

a.当msg.callback不为空时

    a.这在使用post方式发送消息时,会发生

   b.直接调用Runnable的run方法

b.当mCallback不为空时

  a.这在之前的源码分析中我们曾提到,当Handler.callBack为参数构造Handler时调用

  b.那就调用构造函数里传入handlerMessage()方法

  c.如果返回true就不行再往下执行。

c.最后调用handleMessage()这是一个空实现,需要我们在Handler子类里面重写。

5.3移除信息

由于发送时可以发送 Callback 和 Message,所以取消也有两种:

  1. removeCallbacks()
  2. removeMessages()

看一下源码发现调用的其实就是消息队列的出队方法:

public final void removeCallbacks(Runnable r){
    mQueue.removeMessages(this, r, null);
}
public final void removeMessages(int what) {
    mQueue.removeMessages(this, what, null);
}

至此结束:

参考:

1.Android艺术探索

2.https://blog.csdn.net/u011240877/article/details/72892321

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章