Handler(一)

Android知识总结
Android中UI的更新在主线程中完成,为了避免ANR异常所以耗时的操作需要在子线程中完成。由于主线程和子线程中需要消息的传递就引入了Hander消息传递机制。

一、首先看一下handler的使用过程

public class MainActivity extends AppCompatActivity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
               ***
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mHandler.sendEmptyMessage("0");
            }
        }).start();
    }
}

二、handler运行机制

handler之间的通信可见下面两张图:


handler机制
主线程与子线程通信

Handler机制也可叫异步消息机制,它主要由4个部分组成:Message,Handler,MessageQueue,Looper,其中增加了ThreadLocal来管理Looper.

1.Message
  Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。使用Message的arg1和arg2便可携带int数据,使用obj便可携带Object类型数据。target用来保存当前的handler。

2.Handler
  Handler顾名思义就是处理者的意思,它只要用于在子线程发送消息对象Message,在UI线程处理消息对象Message,在子线程调用sendMessage方法发送消息对象Message,而发送的消息经过一系列地辗转之后最终会被传递到Handler的handleMessage方法中,最终在handleMessage方法中消息对象Message被处理。

3.MessageQueue
  MessageQueue就是消息队列的意思,它只要用于存放所有通过Handler发送过来的消息。这部分消息会一直存放于消息队列当中,等待被处理。每个线程中只会有一个MessageQueue对象,请牢记这句话。其实从字面上就可以看出,MessageQueue底层数据结构是队列,而且这个队列只存放Message对象。

4.Looper
  Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当MesssageQueue中存在一条消息,Looper就会将这条消息取出,并将它传递到Handler的handleMessage()方法中。每个线程只有一个Looper对象。

5.ThreadLocal
通过引用ThreadLocalMap的map对象来管理不同线程中的Looper。通过get()/set()方法来获取和存储Looper.

三、handler源码分析

1、发送消息

使用Handler发送消息主要有两种,一种是sendXXXMessage方式,还有一个postXXX方式,不过两种方式最后都会调用到sendMessageDelayed方法,所以我们就以最简单的sendMessage()方法来分析。

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

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

调用sendMessageDelayed()方法,默认delayMillis为0

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

在调用sendMessageAtTime时,传入的时间值: 系统时钟+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;
        }
        // 调用enqueueMessage,把消息加入到MessageQueue中
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //msg.target标记为当前Handler对象
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在MessageQueue中把接受到的Message存到MessageQueue中。然后根据延迟的时间片when把不同得消息存放到Message单链表中,按延迟的时间从小到大从链表头部依次排列。

    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) {
            // 判断消息队列是否正在被关闭,如果是正在被关闭,则return false告诉消息入队
          //是失败,并且回收消息
            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的when并且修改msg的标志位,msg标志位显示为已使用
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
              //根据when的比较来判断要添加的Message是否应该放在队列头部,当第一个添加消息的时候,
            // 测试队列为空,所以该Message也应该位于头部。
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                // 把msg的下一个元素设置为p
                msg.next = p;
                // 把msg设置为链表的头部元素
                mMessages = msg;
                 // 如果有阻塞,则需要唤醒
                needWake = mBlocked;
            } else {
                 //除非消息队列的头部是障栅(barrier),或者消息队列的第一个消息是异步消息,
                //否则如果是插入到中间位置,我们通常不唤醒消息队列,
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                 // 不断遍历消息队列,根据when的比较找到合适的插入Message的位置。
                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;
            } //将消息放到消息头
            if (needWake) {
                nativeWake(mPtr); //在这里进行唤醒
            }
        }
        return true;
    }

2、读取消息

Looper.loop()的作用就是:从当前线程的MessageQueue从不断取出Message,并调用其相关的方法。代码如下:

 public static void loop() {
        //1、里面调用了sThreadLocal.get()获得刚才创建的Looper对象
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //2、获取消息队列, 如果Looper为空则会抛出异常
        final MessageQueue queue = me.mQueue;
        Binder.clearCallingIdentity();
        ***
        for (;;) {
            //3、通过死循环读取MessageQueue中的Message
            Message msg = queue.next(); // might block
            if (msg == null) {
                //由于刚创建MessageQueue就开始轮询,队列里有消息的,等到Handler sendMessageenqueueMessage后队列里才有消息
                return;
            }
            ***
            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
              //4、通过Message中的target找到当前Message中的Handler分发消息
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           
            ***
            //5、回收资源
            msg.recycleUnchecked();
        }
    }

首先还是判断了当前线程是否有Looper,然后得到当前线程的MessageQueue。接下来,就是最关键的代码了,写了一个死循环,不断调用MessageQueue的next方法取出MessageQueue中的Message,注意,当MessageQueue中没有消息时,next方法会阻塞,导致当前线程挂起。

拿到Message以后,会调用它的target的dispatchMessage方法,这个target其实就是发送消息时用到的Handler。所以就是调用Handler的dispatchMessage方法,代码如下:

 public void dispatchMessage(Message msg) {
        // 如果msg.callback不是null,则调用handleCallback
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            // 如果 mCallback不为空,则调用mCallback.handleMessage方法
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // 调用Handler自身的handleMessage,这就是我们常常重写的那个方法
            handleMessage(msg);
        }
    }
    public void handleMessage(Message msg) {
    }

回收Message, 调用Message中的recycleUnchecked方法:

    //最大队列个数为50
    private static final int MAX_POOL_SIZE = 50;
    private static Message sPool;

    @UnsupportedAppUsage
    void recycleUnchecked() { 
        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;
        //把message放在链表的头部
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                //把message放在sPool中构成一个链表回路
                //运用享元设计模式,提供内存复用,避免内存抖动造成的OOM
                sPool = this;
                sPoolSize++;
            }
        }
    }
3、ActivityThread

主线程中在ActivityThread的main方法中创建Looper对象,所以在主线程中创建Hander时不用创建Looper对象。在子线程中需要手动创建Looper对象。

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        CloseGuard.setEnabled(false);
        Environment.initForCurrentUser();
        EventLogger.setReporter(new EventLoggingReporter());
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);
        Process.setArgV0("");
        //1、创建Looper,并将Looper保存到ThreadLocal中
        Looper.prepareMainLooper();
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        //把ActivityThread 和主线程进行绑定
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
          //2、开启死循环读取消息
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
4、Looper机制

创建Looper

   public static void prepare() {
        //消息队列可以quit
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        //不为空表示当前线程已经创建了Looper
        if (sThreadLocal.get() != null) {
            //每个线程只能创建一个Looper
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //创建Looper并设置给sThreadLocal,这样get的时候就不会为null了
        sThreadLocal.set(new Looper(quitAllowed));
    }

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

从上面的代码可以看出,一个线程最多只有一个Looper对象。当没有Looper对象时,去创建一个Looper,并存放到sThreadLocal中。

private Looper(boolean quitAllowed) {
        //创建了MessageQueue
        mQueue = new MessageQueue(quitAllowed); 
        //当前线程的绑定
        mThread = Thread.currentThread();
 }

这里主要就是创建了消息队列MessageQueue,并让它供Looper持有,因为一个线程最大只有一个Looper对象,所以一个线程最多也只有一个消息队列。然后再把当前线程赋值给mThread。
MessageQueue的构造方法没有什么可讲的,它就是一个消息队列,用于存放Message。
所以Looper.prepare()的作用主要有以下三点
1、创建Looper对象
2、创建MessageQueue对象,并让Looper对象持有
3、让Looper对象持有当前线程

5、ThreadLocal

通过引用ThreadLocalMap的map对象来管理不同线程中的Looper。通过get()/set()方法来获取和存储Looper.

    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);
    }
6、Message

成员变量

   // 回复跨进程的Messenger 
    public Messenger replyTo;
    // Messager发送这的Uid
    public int sendingUid = -1;

    // 正在使用的标志值 表示当前Message 正处于使用状态,当Message处于消息队列中、
    //处于消息池中或者Handler正在处理Message的时候,它就处于使用状态。
    /*package*/ static final int FLAG_IN_USE = 1 << 0;
    // 异步标志值 表示当前Message是异步的。
    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
    // 消息标志值 在调用copyFrom()方法时,该常量将会被设置,其值其实和FLAG_IN_USE一样
    /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
    // 消息标志,上面三个常量 FLAG 用在这里
    /*package*/ int flags;
    // 用于存储发送消息的时间点,以毫秒为单位
    /*package*/ long when;
    // 用于存储比较复杂的数据
    /*package*/ Bundle data;
    // 用于存储发送当前Message的Handler对象,前面提到过Handler其实和Message相互持有引用的
    /*package*/ Handler target;
    // 用于存储将会执行的Runnable对象,前面提到过除了handlerMessage(Message msg)
    //方法,你也可以使用Runnable执行操作,要注意的是这种方法并不会创建新的线程。
    /*package*/ Runnable callback;
    // 指向下一个Message,也就是线程池其实是一个链表结构
    /*package*/ Message next;
    // 该静态变量仅仅是为了给同步块提供一个锁而已
    private static final Object sPoolSync = new Object();
    //该静态的Message是整个线程池链表的头部,通过它才能够逐个取出对象池的Message
    private static Message sPool;
    // 该静态变量用于记录对象池中的Message的数量,也就是链表的长度
    private static int sPoolSize = 0;
    // 设置了对象池中的Message的最大数量,也就是链表的最大长度
    private static final int MAX_POOL_SIZE = 50;
     //该版本系统是否支持回收标志位
    private static boolean gCheckRecycle = true;

获取消息

    public static Message obtain() {
       // 保证线程安全
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                 // flags为移除使用标志
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

   public static Message obtain(Handler h) {
        Message m = obtain();
        //记录Hander对象
        m.target = h;
        return m;
    }

7、MessageQueue成员变量
    //用于标示消息队列是否可以被关闭,主线程的消息队列不可关闭
    private final boolean mQuitAllowed;
    @SuppressWarnings("unused")
    // 该变量用于保存native代码中的MessageQueue的指针
    private long mPtr; // used by native code
    //在MessageQueue中,所有的Message是以链表的形式组织在一起的,该变量保存了
    //链表的第一个元素,也可以说它就是链表的本身
    Message mMessages;
    //当Handler线程处于空闲状态的时候(MessageQueue没有其他Message时),可以利用
    //它来处理一些事物,该变量就是用于保存这些空闲时候要处理的事务
    private final ArrayList mIdleHandlers = new ArrayList();
    // 注册FileDescriptor以及感兴趣的Events,例如文件输入、输出和错误,设置回调函数,最后
    // 调用nativeSetFileDescriptorEvent注册到C++层中,
    // 当产生相应事件时,由C++层调用Java的DispathEvents,激活相应的回调函数
    private SparseArray mFileDescriptorRecords;
     // 用于保存将要被执行的IdleHandler
    private IdleHandler[] mPendingIdleHandlers;
    //标示MessageQueue是否正在关闭。
    private boolean mQuitting;
    // 标示 MessageQueue是否阻塞
    private boolean mBlocked;
    // 在MessageQueue里面有一个概念叫做障栅,它用于拦截同步的Message,阻止这些消息被执行,
    // 只有异步Message才会放行。障栅本身也是一个Message,只是它的target为null并且arg1用于区分不同的障栅,
     // 所以该变量就是用于不断累加生成不同的障栅。
    private int mNextBarrierToken;

next()方法

     //销毁
     private native static void nativeDestroy(long ptr);
    //延时
    private native void nativePollOnce(long ptr, int timeoutMillis);
    //唤醒
    private native static void nativeWake(long ptr);

Message next() {
        // 如果消息循环已经退出了。则直接在这里return。因为调用disposed()方法后mPtr=0
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }
        //记录空闲时处理的IdlerHandler的数量
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        // native层用到的变量 ,如果消息尚未到达处理时间,则表示为距离该消息处理事件的总时长,
        // 表明Native Looper只需要block到消息需要处理的时间就行了。 所以nextPollTimeoutMillis>0表示还有消息待处理
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                //刷新下Binder命令,一般在阻塞前调用
                Binder.flushPendingCommands();
            }
            // 调用native层进行消息标示,nextPollTimeoutMillis 为0立即返回,为-1则阻塞等待, 大于0延时一定时间。
            nativePollOnce(ptr, nextPollTimeoutMillis);
            //加上同步锁
            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                // 获取开机到现在的时间
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                // 获取MessageQueue的链表表头的第一个元素
                Message msg = mMessages;
                 // 判断Message是否是障栅,如果是则执行循环,拦截所有同步消息,直到取到第一个异步消息为止
                if (msg != null && msg.target == null) {
                     // 如果能进入这个if,则表面MessageQueue的第一个元素就是障栅(barrier)
                    // 循环遍历出第一个异步消息,这段代码可以看出障栅会拦截所有同步消息
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                       //如果msg==null或者msg是异步消息则退出循环,msg==null则意味着已经循环结束
                    } while (msg != null && !msg.isAsynchronous());
                }
                 // 判断是否有可执行的Message
                if (msg != null) {  
                    // 判断该Mesage是否到了被执行的时间。
                    if (now < msg.when) {
                        // 当Message还没有到被执行时间的时候,记录下一次要执行的Message的时间点
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Message的被执行时间已到
                        // Got a message.
                        // 从队列中取出该Message,并重新构建原来队列的链接
                        // 刺客说明说有消息,所以不能阻塞
                        mBlocked = false;
                        // 如果还有上一个元素
                        if (prevMsg != null) {
                            //上一个元素的next(越过自己)直接指向下一个元素
                            prevMsg.next = msg.next;
                        } else {
                           //如果没有上一个元素,则说明是消息队列中的头元素,直接让第二个元素变成头元素
                            mMessages = msg.next;
                        }
                        // 因为要取出msg,所以msg的next不能指向链表的任何元素,所以next要置为null
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        // 标记该Message为正处于使用状态,然后返回Message
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    // 没有任何可执行的Message,重置时间
                    nextPollTimeoutMillis = -1;
                }

                // 关闭消息队列,返回null,通知Looper停止循环, 只有在子线程中可以调用用
                if (mQuitting) {
                    dispose();
                    return null;
                }
                // 当第一次循环的时候才会在空闲的时候去执行IdleHandler,从代码可以看出所谓的空闲状态
                // 指的就是当队列中没有任何可执行的Message,这里的可执行有两要求,
                // 即该Message不会被障栅拦截,且Message.when到达了执行时间点
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                
                // 这里是消息队列阻塞( 死循环) 的重点,消息队列在阻塞的标示是消息队列中没有任何消息,
                // 并且所有的 IdleHandler 都已经执行过一次了
                if (pendingIdleHandlerCount <= 0) {
                    mBlocked = true;
                    continue;
                }
    
                // 初始化要被执行的IdleHandler,最少4个
                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }
            // 开始循环执行所有的IdleHandler,并且根据返回值判断是否保留IdleHandler
            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);
                    }
                }
            }

            // 重点代码,IdleHandler只会在消息队列阻塞之前执行一次,执行之后改标示设置为0,
            // 之后就不会再执行,一直到下一次调用MessageQueue.next() 方法。
            pendingIdleHandlerCount = 0;
            // 当执行了IdleHandler 的 处理之后,会消耗一段时间,这时候消息队列里的可能有消息已经到达 
             // 可执行时间,所以重置该变量回去重新检查消息队列。
            nextPollTimeoutMillis = 0;
        }
    }

    private void dispose() {
        if (mPtr != 0) {
            //退出时调用native方法,关闭消息队列
            nativeDestroy(mPtr);
            mPtr = 0;
        }
    }

Handler线程里面实际上有两个无线循环体,Looper循环体和MessageQueue循环体,真正阻塞的地方是MessageQueue的next()方法里。

    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;
            if (p == null || when == 0 || when < p.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;
            }

            // 如果处于等待状态,唤醒
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

Looper退出

Looper

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

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

MessageQueue

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

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            //退出时标志为至true
            mQuitting = true;
            //清楚队列中的消息
            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }
            nativeWake(mPtr);
        }
    }

    private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }

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

四、runWithScissors 同步执行

Handler 的 setxx 或者 postxx 发送消息是异步的并不会阻塞程序的执行。runWithScissors是同步消息,可以通过阻塞的方式,向目标线程发送任务,并等待任务执行结束。

    public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
        if (r == null) {
            throw new IllegalArgumentException("runnable must not be null");
        }
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout must be non-negative");
        }

        if (Looper.myLooper() == mLooper) {
            r.run();
            return true;
        }

        BlockingRunnable br = new BlockingRunnable(r);
        return br.postAndWait(this, timeout);
    }
private static final class BlockingRunnable implements Runnable {
    private final Runnable mTask;
    private boolean mDone;

    public BlockingRunnable(Runnable task) {
        //把任务赋值给mTask
        mTask = task;
    }

    @Override
    public void run() {
        try {
        //执行这个任务
            mTask.run();
        } finally {
            synchronized (this) {
            //任务执行完毕,标记mDone为true,并唤醒等待线程
                mDone = true;
                notifyAll();
            }
        }
    }

    public boolean postAndWait(Handler handler, long timeout) {
    //把本身的BlockingRunnable发送到handler线程中执行
        if (!handler.post(this)) {
            return false;
        }

        synchronized (this) {
            if (timeout > 0) {
                final long expirationTime = 
                SystemClock.uptimeMillis() + timeout;
                while (!mDone) {
                    long delay = expirationTime - SystemClock.uptimeMillis();
                    if (delay <= 0) {//超时返回
                        return false; // timeout
                    }
                    try {//否则一直等待
                        wait(delay);
                    } catch (InterruptedException ex) {
                    }
                }
            } else {//如果没有设置超时,则一直等待
                while (!mDone) {
                    try {
                        wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }
        return true;
    }
}

由此可见使用 runWithScissors() 可能造成调用线程进入阻塞,而得不到唤醒,如果当前持有别的锁,还会造成死锁。

你可能感兴趣的:(Handler(一))