直接干!
new一个handler不带参数的时候,callback默认为null(没有回调),async为false(非同步调用)。
看上去是用了一个现成的Looper,将looper里的消息队列赋值到自己的队列,callback一看就知道是有了消息之后的回调,async我们后面再看看具体应用场景
可以看到,他们都是发送的sendMessageDelayed。
然后看看getPostMessage里面干了什么:
将runnable封装成了一个Message对象,但是我们使用handler.send的时候好像没有这一步,只是将Message.what进行了赋值,不妨猜想一下,等执行sendMessage的时候执行的是new Handler对象的callback回调(也就是handleMessage),而执行到post(runnable)的时候执行的Message里的callback(即runnable的run方法)。带着这个疑问继续往下看
见名知意,将Message设置好target(Handler)和async(同步)插入到消息队列MessageQueue中。
那么在这里,首先判断了消息队列是否在退出(折射到线程是否在退出)。
如果不是,先判断Message的when是不是在队列最开始的Message前面(when即Message的延迟执行时间)。是的话就插入到队列最前端,否则插入按照延迟执行的时间插入到队列中。然后根据线程是否blocked来决定是否要唤醒线程。
引申:如果主线程没有消息了,Looper会不断循环是否有消息,会造成CPU的负担吗?
答:到了这里我们可以看到,如果Looper没有消息队列的话,会进入blocked状态,减少CPU的消耗。
那么既然插入到消息队列了,我们都知道是Looper来进行消息的消费,那我们来看看到底是怎么执行的。
那直接看loop方法:
标记1处我们可以看到,通过myLooper方法获取到Looper对象,具体过程为调用ThreadLocal的get方法,用我们的线程做key,获取到线程的ThreadLocalMap对象(线程独有, 不与其他线程共享)即获取到Looper对象,如果为null,就进行初始化,
可以看到,默认初始,化为null,但是这里使用了protected进行方法的修饰,那么我们就可以通过自定义TheadLocal进行默认的Looper对象的初始化,这里以后再进行尝试。
继续回到loop方法中,终于进到for循环了
第一行可以看到,是在进行MessageQueue的遍历,除了圈出来的,其他都是进行系统的log日志填写,而圈出来的方法,则是在进行Message的分发,那我们来看它干了啥
果然如此!验证了上面的猜想,先看Message的callback是否为空,不为空使用Message的callback进行回调(post一个runnable),为空的话就调用handleMessage进行回调(send一个Message)
接下来也没啥重要的了,来看下recycleUncheked干了啥。
这里将next只想sPool(上一个重置属性的Message),然后将sPool指向自己(当前正在使用的Message),回收池数量增加。那么我们可以看到回收池数量有个上限(50个),啥时候才会减少呢?
我们可以明白,是从回收池中获取一个Message(上面recycle使我们知道回收的时候是将除了标记,其他所有属性都抹去了),如此我们可以避免新建一个Message,多增加内存开销。
最后我们来看一下next到底干了什么:
从上往下:
nextPollTimeoutMillis表示距离下一个需要处理的Message的时间,当没有消息时,该值为-1,如果不为0,将Binder里的写操作完成(native), 防止它被阻塞
然后调用nativePollOnce来进行延时唤醒(在这期间如果有其他操作能立即唤醒,也就是nativeWake)
接下来进入第一个循环,也就是设置同步屏障后(Message.target == null)的异步消息,这里在上图已经标明,异步消息需要先执行
当队列中没有消息或者指针指向的消息是一个异步消息的时候,就会执行IdleHandler,之后会将pendingIdleHandlerCount赋值0,也就永远不会执行idleHandler了