Android 的一种消息传递机制,用于异步处理
为了保证线程安全,Android 只允许主线程更新UI,如果工作线程想要更新UI必须让主线程执行,Handler的出现就是用于工作线程与主线程间的通信
主线程(UI线程):ActivityThread,APP启动时会自动启动一条主线程用于执行UI更新操作
工作线程:用于执行耗时任务(网络请求、计算),避免出现ANR
消息:Message,线程通信的数据单元
消息队列:MessageQueue,先进先出的数据结构(单链表),用于存放消息
处理器:Handler,一个Handler实例必须与一个Looper对象关联,当你创建一个新的Handler,它会和一个Looper进行绑定(不一定是当前线程的Looper,其他线程创建好的Looper也可以),它将向Looper关联的的消息队列发送消息,并在Looper的线程上执行它们
循环器:Looper,一个线程持有一个Looper,一个Looper持有一个MessageQueue,但是一个Looper可以与多个Handler绑定,这样多个Handler将消息传给同一个Looper的消息队列中,由Looper将消息取出分发给不同的Handler(与它绑定的Handler们),从而实现线程通信
定义
class MyHandler extends Handler {//子类
@override
public void handleMessage(Message msg) {
//用于处理接收到的消息
}
}
private Handler myHandler = new Handler() {//匿名内部类
@override
public void handleMessage(Message msg) {
//用于处理接收到的消息
}
};
发送
//1.sendMessage()
private Handler myHandler = new MyHandler();
Message msg = Message.botain();
msg.what= 0x22;
msg.msg = 1;
myHandler.sendMessage(msg);
//2.post()
//在主线程中创建Handler对象myHandler,在工作线程中使用该对象执行post()方法
myHandler.post(new Runnable(){
@override
public void run() {
//直接写你要干什么
}
})
这两种使用方式底层都是调用了同一个方法sendMessageDelayed,最终通过MQ中的enqueueMessage方法实现消息入队
在线程中创建处理器Handler、循环器Looper及消息队列MessageQueue的对象;主线程创建时自动创建Looper和MessageQueue,工作线程需要手动创建。
Handler将Message发送到与自己绑定的Looper的MessageQueue
在消息循环的过程中,如果MQ为空了,线程会阻塞
Handler拿到Looper发来的Message后执行操作
下面是Handler实现简单线程通信的示意图:
创建Handler
//经常使用的构造器
public Handler() {
this(null, false);
}
//指定Looper的构造器
public Handler(Looper looper) {
this(looper, nuul, false);
}
public Handler(Callback callback, boolean async) {
...
1.指定Looper对象,因为没有指定Looper,所以绑定当前线程的Looper
mLooper = Looper.myLooper();
Handler必须绑定一个Looper对象否则抛异常;所以工作线程中创建Handler之前必须先创建Looper对象
if (mLooper == null) { throw new RuntimeException(); }
2.绑定消息队列对象
mQueue = mLooper.mQueue;
}
public Handler(Looper looper, Callback callback, boolean async) {
...
1.指定Looper对象,因为指定了Looper对象,所以可以直接绑定
mLooper = looper;
2.绑定消息队列对象
mQueue = looper.mQueue;
}
发送消息
//sendMessage
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
//post
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;
}
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) {
发送消息前先获取到与Handler绑定的Looper对象持有的MQ
MessageQueue queue = mQueue;
MQ对象必须有,否则无法发送消息
if (queue == null) { return false; }
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
Handler把消息发送到MQ
return queue.enqueueMessage(msg, uptimeMillis);
}
分发、处理消息
public void dispatchMessage(Message msg) {
1.处理post方法发出的消息
if (msg.callback != null) {
handleCallback(msg);//也就是回调Runnable中的run方法
} else {
...
2.处理sendMessage方法发出的消息
handleMessage(msg);
}
}
创建Looper对象
public static void prepare() {
prepare(true);
}
public static void prepareMainLooper() {
1.在android系统启动时,会默认创建一个主线程也叫UI线程ActivityThread,会自动调用它的main方法
prepare(false);
...
sMainLooper = myLooper();
}
private static void prepare(boolean quitAllowed) {
1.先判断当前线程中有没有Looper对象,因为一个线程只能有一个Looper对象,所以该方法只能调用一次
if (sThreadLocal.get() != null) {
throw "Only one Looper may be created per thread"
}
2.将Looper对象存放到Thread里
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
1.只要创建了Looper就自动创建了MQ对象
mQueue = new MessageQueue(quitAllowed);
...
mThread = Thread.currentThread();
}
开启消息循环
public static void loop() {
1.获取当前Looper的消息队列
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
...
2.消息循环
for(;;) {
2.1 从消息队列中取出消息
Message msg = queue.next();
if (msg == null) {//若取出的消息为空,则线程阻塞
return;
}
2.2 派发消息到对应的Handler
msg.target.dispatchMessage(msg);//把消息派发给message的target属性;target属性实际就是一个Handler对象
3.释放消息占据的资源
msg.recycleUnchecked();//其实就是将message里面的属性都赋值0或null
}
}
Message next() {
...
1.用于标识队中是否还有消息 0:还有 -1:没了
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
2.如果nextPollTimeoutMillis等于-1,队列处于等待状态
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
...
if (msg != null) {
...
3.消息出队
return msg;
} else {
4.没有消息了
nextPollTimeoutMillis = -1;
}
}
}
}
boolean enqueueMessage(Message msg, long when) {
...
synchronized(this) {
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
1.判断消息队列里有没有消息
if (p == null || when = 0 || when < p.when) {
2.若没有消息,将当前插入消息作为队头;若此消息队列处于阻塞态,则唤醒
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
...
for(;;) {
3.若有消息,根据消息创建时间插入队列
}
}
}
}
public static Message obtain() {
1.Message内部维护了一个Message池,用于Message对象的复用,使用obtain方法就是直接从池内获取
synchronized (sPoolsSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;//Message是链表?
m.flags = 0;
sPoolSize--;
return m;
}
}
2.若池内无消息对象可用,则还是用关键字new创建
return new Message();
}
Message内部有很多属性,比如target是Handler等等,可以好好看看
public static void main(String[] args) {
...
1.默认为主线程创建一个Looper对象,同时生成一个MQ对象
Looper.prepareMainLooper();
2.创建主线程
ActivityThread thread = new ActivityThread();
3.开启消息循环
Looper.loop();
}