背景
在Android中,只有在UIThread中才能直接更新界面
在Android中,长时间的工作(联网)都需要在workerThread中执行
在分线程获得服务器数据后, 需要立即到主线程去更新界面显示数据(这就需要通信)
如何实现线程间通信呢?
下面我们来了解:Android里面的消息机制和异步任务
API
Message :消息
可理解为线程间通讯的数据单元, 可通过message携带需要的数据
创建对象: Message.obtain(what)
封装数据
public int what //id 标识
public int arg1
public int arg2
public Object obj
Handler : 处理器
Handler是Message的处理器,同时也负责消息的发送和移除的工作
发送即时消息: sendMessage(Message msg)
发送延时消息: sendMessageDelayed(Message msg, long time)//延迟处理,不是延迟发送,也会立即发送的
处理消息: handleMessage(Message msg) (回调方法)
移除还未处理的消息: removeMessages(int what)
MessageQueue : 消息队列
用来存放通过Handler发送的消息
它是一个按Message的when排序的优先级队列
Looper(钩子) : 循环器
负责循环取出Message Queue里面的当前需要处理的Message
交给对应的Handler进行处理
处理完后, 将Message缓存到消息池中, 以备复用
消息机制原理
图解
Message
/*
* Message类:
* public int what; id标识
* public int arg1; 保存int的数据
* public int arg2; 保存int的数据
* public Object obj;保存任意数据
* long when; 记录应该被处理的时间值
* Handler target; 用来处理消息的Handler对象,就是保存用来发送消息的Handler
* Runnable callback; 用来处理消息的回调器
* Message next; 下一个Message,形成链表的结构
* private static Message sPool; 用来缓存处理过的Message,用来复用
*
* Runnable对象的run()什么时候在分线程执行?
* 将Runnable传给Thread的构造方法的时候,比如:
* new Thread(new Runnable(){
* public void run(){} //这个就是在分线程执行
* }).start();
*/
Handler
/*
* Handler类:
* 作用:发送消息,处理消息,移除消息
* sendMessage(Message msg) 调用sendMessageDelayed(msg, 0);
*
* sendEmptyMessage(int what) 调用 sendEmptyMessageDelayed(what, 0);
* 进入里面看
* public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
其实发送空消息就是发送不带数据的消息
上面调用最多的就是sendMessageDelayed(Message msg, long delayMillis),进入查看一下
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
所以发送延迟消息就是发送的当前时间加上延迟的时间
进入sendMessageAtTime这个方法查看
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, 0);
}
进入enqueueMessage(queue, msg, 0);
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//这个就是将消息的target设置成当前的Handler,就是发送消息的Handler
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//然后调用了消息队列里面的方法将消息加入消息队列
return queue.enqueueMessage(msg, uptimeMillis);
}
移除消息
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
处理消息,需要重写的
public void handleMessage(Message msg) {
}
派发消息
public void dispatchMessage(Message msg) {
//如果消息自己可以处理,就让消息自己处理,就是看消息有没有重写callback方法
if (msg.callback != null) {
handleCallback(msg);
} else {
//如果Handler对象中有回调监听器,调用回调监听器来处理消息,
//回调监听器如果返回的是true,就会处理完毕,比如又会继续调用handleMessage
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
*/
MessageQueue
/*
MessageQueue类:这是储存消息的队列,以message的when排序的优先级队列
enqueueMessage(Message msg, long when)//将message添加到队列中
里面的队列排序的原理也很简单,可以查看一下
boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {
throw new AndroidRuntimeException("Message must have a target.");
}
boolean needWake;
synchronized (this) {
if (mQuiting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
}
msg.when = when;
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
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;
}
取出一个Message对象,但是可能不会立即返回
Message next() 里面取出消息队列中的第一个消息,然后返回
里面调用了nativePollOnce(mPtr, nextPollTimeoutMillis);方法
这个本地方法会导致处于处理等待状态,但是不会阻塞主线程
*/
Looper
Looper类:这个方法在系统启动的时候就启动了
作用是从MessageQueue中获取当前需要处理的消息,并交给Handler处理
public static void loop() {
//获取当前的钩子
final Looper me = myLooper();
//获取消息队列
final MessageQueue queue = me.mQueue;
for (;;) {
//这里虽然是无限for循环,但是这个获取下一个消息可能会处于阻塞状态
Message msg = queue.next(); // might block
//调用Handler去分发消息并且处理消息
msg.target.dispatchMessage(msg);
//回收利用消息
msg.recycle();
}
}
异步任务AsyncTask
简介
什么是异步任务?
逻辑上: 以多线程的方式完成的功能需求
API上: 指AsyncTask类
AsyncTask的理解
在没有AsyncTask之前, 我们用Handler+Thread就可以实现异步任务的功能需求
AsyncTask是对Handler和Thread的封装, 使用它更编码更简洁,更高效
AsyncTask封装了ThreadPool, 比直接使用Thread效率要高