Handler的流程和原理是老生常淡的问题了,无论是面试还是日常工作中,熟悉handler流程是比较重要的。这篇文章也是我第一次写博客。从事android多年,一直没有写过博客,一直是看别人写的博客。最近才想要写博客,所以说干就干。我想,我写博客的目的应该是写给自己看,做记录,如果这篇文章能对大家理解handler有所帮助,我也很高兴。
从源码角度看handler的工作流程
首先从handler的 sendMessage(msg) 方法开始看,因为这个方法是离我们开发者最近的一个方法,也是一个源码入口方法。sendMessage()会在内部调用其延时发送消息的sendMessageDelayed()。然后在sendMessageDelayed()方法中获取当前系统时间的毫秒值和传递的延时时间的毫秒值作为when参数,传递到sendMessageAtTime()方法。
在sendMessageAtTime()方法中获取与当前线程的looper绑定的messageQueue。如messageQueue不存在则说明当前线程没有实例化looper。这也是为什么会出现在子线程中使用handler需要通过Looper.prepare()方法初始化Looper的现象的原因。而在主线程已经在ActivityThread的main方法中已经初始化过了,所以在主线程中不需要。在此方法的最后调用enqueueMessage(queue,msg,uptimeMillis)做让message加入队列前的准备。主要是将message的target设置成当前的handler.即将message和当前的handler绑定,在接收message时用到。最后调用MessageQueue中的enqueueMessage方法让message入链。
现在让我们来到MessageQueue类中的enquequeMessage方法,此方法的主要逻辑是将每一个message通过when的先后进行排序,并使用单链表的方式串联起来。并按照发送时间的先后插入和当前线程通过looper绑定绑定messageQueue中。在这一步中依然还没有调用handler发送消息的方法。
接下来我们看下Looper的loop方法,在这个方法里,通过msg的target.dispatchMessage()方法将message发送到原来的Handler中。这个target和message的绑定,也是message能准确发送回原来handler的原因。在这个方法里,还有一个重要的方法Message msg = queue.next(); 这个方法在取出消息的for循环里。这个for循环是死循环,只有当取出的message为null时退出循环。
MessageQueue中取出消息的next方法也是一个保证message能够按时发送的方法,主要是通过获取message中的when,这个是sendMessage时设置的。使用when和当前系统时间进行比较。小于或者等于0是可以马上取出给到looper.loop中发送。如果when大于0,则通过nativePollOnce(ptr, nextPollTimeoutMillis)方法对取出消息进行阻塞,直到when等于当前系统时间。这个是保证message能准确时间点发送的原因。 这时,我们的整个handler的机制已经全部走完了。
总结
Handler是用来发送和接收消息的,并将消息传递给MessageQueue。Handler初始化时会默认指定当前线程的looper。此looper通过静态的sThreadLocal来保证唯一,即一个线程只能创建一个looper。通过ThreadLocalMap将当前线程和looper进行绑定。
Messagequeue是一个单链表,负责message的入链和排序。并在looper通过MessageQueue.next()方法取出消息未到消息发送时间前对线程进行阻塞。保证消息的时效性。
Looper负责循环从MessageQueue中取出message,并交给message的target,这条message绑定的Handler进行dispatchMessage(msg),并让message对当前msg进行回收。
Message是消息的载体,包含消息本身和target的handler,负责消息载体的recycleUnchecked回收和obtain复用,最大message条数MAX_POOL_SIZE为50
网友评论