what
在Android开发中,Hanldler消息机制可以说无处不在,主线程的调度,View,任务提交,IntentService,Messager中都出现了,可谓无处不在。handler消息发挥作用的包含了:Handler,Looper,Message,MessagerQueue,这四个重要组成。Handler发送消息,Looper开启轮询从MessageQueue中获取消息,交由Handler处理。
how
还是从一个使用者角度先了解,具体怎么用Handler吧。
1 | private Handler mHandler = new Handler(Looper.getMainLooper()){ |
创键Handler对象,传入Looper,发送消息。再Hanlder内部处理消息,当然还可以直接发送Runnable,或者加入延时等。用法就这么简单。下面还是具体介绍吧
Handler
可以发送消息和处理消息,可以有很多个实例,具体根据消息来分辨处理。
它的成员包括了Looper,MessageQueue,Callback
1 | //常用api,以及加上延时等 |
一般使用Handler有两种方法,一般是需要传入Looper,如果不则默认传入当前线程的Looper
- 扩展Handler,重写handleMessage
- 传入回调,回调也只需要实现handleMessage
1 | //最终被调用的构造器 |
Looper
这个的话管他叫轮询,反正是有循环的意思。首先它是一个ThreadLocal变量,保证了每个线程间独立运行,再而它的话就是从消息队列中取出消息,转交到Handler处理
它的成员包括了ThreadLocal,MessageQueue,Thread。
看下重要api
1 | prepare();//获取线程本地Looper实例 |
Message
封装了消息码,触发时机,runnable,目标handler的消息,内部是一个长度50不断复用的消息池(链表结构),消息分为异步和同步
看下重要api
1 | Message.obtain();//从池里获得消息 |
MessageQueue
尾插法实现的消息链表,异步消息优先出,称之为消息队列,但是不是那个操作系统的消息队列啊。
1 | next();//拿取消息 |
从源码来角度再探析
本来向从主线程来分析的,但是好像不怎么完整,那就用HandlerTread来分析吧,这个就非常完整了
HandlerThread
首先这是一个Thread,内部实现了Handler消息机制,即可以通过Handler来进行提交任务和消息到线程中运行。
先看下是怎么用的:
1 | HandlerThread handlerThread = new HandlerThread("test");//创键HandlerThread |
用就是这么用的。原理就是handler提交消息,HandlerThread线程开启轮询,分发消息,处理。
接下来就可以分析源码了:
HandlerThread构造
首先进入HandlerThread构造方法
1 | public HandlerThread(String name) { |
HandlerThread进入run
接着线程开启进入run方法:
1 | //HandlerThread.run |
在run方法中等于说准备looper,进入轮询
准备Looper
接着看下如何准备Looper和获得Looper的:
1 | //Looper.prepare |
进入Looper轮询
接下就是重头戏了,进入轮询,挑关键代码看看
1 | //Looper.loop |
整个过程也还好理解,开启死循环,从消息队列中不断的拿去消息,然后由消息目标 handler进行分发处理。
接下我先看简单的handler如何分发处理消息的。待会再看如何获取消息的
消息处理
1 | //Handler.dispatchMessage |
分发消息比较简单,首先判断这个消息是否是Runnable类型,是则直接调run,不是的在看是由本身的handleMessage处理还是回调的handleMessage处理。
取出消息
接着就看如何获取消息的:
1 | //MessageQueue.next |
MessageQueue中next中进入死循环获取消息,从队列中去拿去消息,遍历队列消息,队列的消息是按照执行时刻从小到大排列的,根据当前时刻取出该执行的消息(优先取异步消息),如果时机未到则会进入空闲等待(基于linux的管道)。等到了时机则会取出消息。
这一路下来从Looper轮询,消息取出,消息执行的步骤。
接下看看是如何提交消息的
构建消息
构建消息,首先从消息复用池拿去
1 | //Message.obtain |
提交消息
接着Handler提交消息,无论是runnable消息,或者空消息,或者其它的消息,或者带延时的,最终sendMessageAtTime
1 | //Handler.sendMessageAtTime |
消息入队列
接着就是进入消息队列,执行时刻小的在前插入
1 | boolean enqueueMessage(Message msg, long when) { |
差不多流程就是这样了。这个例子使用HandlerThread做示范的,UI主线程同样也是使用这样的实现的。
IntentService
内部实现HandlerThread的Servcie,开启子线程执行,代码比较简单直接截下来了,构建HandlerThread,Handler,在onStartCommand中发送消息,并最终在onHandleIntent响应执行。
1 | public abstract class IntentService extends Service { |