Message
这个是消息的载体,可以用来存放消息,可以存放的内容有以下几种。
- what(int):用来定义Message属于何种操作。
- obj (object):用来传递一个对象,但是要注意的是,在不同的进程中不好用,因为要用Parcelable序列化它。
- arg1(int):int 型数据。
- arg2(int):int型数据。
- Bundle: 可以支持大量的数据类型。 此外,getTarget(),方法可以取得该消息的Handler对象。
Looper
个人感觉Looper有点像NIO中的Selector,它在一个单独的线程当中,可以将不同的Message发送到属于他们的Handler中去,每个线程只有一个Looper。 使用Hander处理Message需要通过Looper来完成。在ActivityThread中,系统会自动帮用户启动Looper,而在其它线程,需要用户手动调用Looper类中的方法,然后才可以正常启动Looper对象,Looper用来让一个普通线程变成Looper线程。 如下可以让一个普通线程变成一个Looper线程。
public class LooperThread extends Thread {
@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();
// ...其他处理,如实例化handler
// 开始循环处理消息队列
Looper.loop();
}
}
prepare 方法
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 试图在有Looper的线程中再次创建Looper将抛出异常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
会发现该方法会创建一个Looper对象,但是要注意的是只会有一个Looper对象,如果第二次进入并创建的话会抛出异常。 loop 方法,该方法也很简单,就是将消息发送给对应的Handler即可,(每个Message会标明属于哪个Handler)。
public static final void loop() {
Looper me = myLooper(); //得到当前线程Looper
MessageQueue queue = me.mQueue; //得到当前looper的MQ
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 开始循环
while (true) {
Message msg = queue.next(); // 取出message
if (msg != null) {
if (msg.target == null) {
// message没有target为结束信号,退出循环
return;
}
// 日志
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
// 非常重要!将真正的处理工作交给message的target,即后面要讲的handler
msg.target.dispatchMessage(msg);
// 日志
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf("Looper", "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
// 回收message资源
msg.recycle();
}
}
}
逻辑是得到当前线程的Looper→得到消息队列→循环取出消息(如果消息Target为空则退出,每个消息使用完时进行回收)。
Handler
有了Message(发送的数据),有了Looper(数据分发员),接着当然就是Handler(处理数据)了。 handler起到了处理MQ(消息队列)上的消息的作用(只处理由自己发出的消息),handler的创建会关联一个looper(默认关联当前线程的looper,不过这也可以set)。 构造方法如下:
public class handler {
final MessageQueue mQueue; // 关联的MQ
final Looper mLooper; // 关联的looper
final Callback mCallback;
// 其他属性
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName());
}
}
// 默认将关联当前线程的looper
mLooper = Looper.myLooper();
// looper不能为空,即该默认的构造方法只能在looper线程中使用
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上
mQueue = mLooper.mQueue;
mCallback = null;
}
// 其他方法
}
需要注意的是:主线程会自动创建Looper,其他线程要手动创建,创建方法在Looper那里。 当然也可以通过有参构造传入一个Looper。 如下:
Handler handler= new Handler(Looper.getMainLooper());
有了Handler后我们就可以为之前的Looper线程添加Handler了
public class LooperThread extends Thread {
private Handler handler1;
private Handler handler2;
@Override
public void run() {
// 将当前线程初始化为Looper线程
Looper.prepare();
// 实例化两个handler
handler1 = new Handler();
handler2 = new Handler();
// 开始循环处理消息队列
Looper.loop();
}
}
线程终于有handler了,接着我们就可以通过handler来处理和发送数据了。
有了Handler后,此时的关系图如上,可以发现:
- 每个LooperThread(Looper线程,怎么来的?,升级来的!!!)只有一个Looper。
- 每个LooperThread可以有多个Handler,每个Handler都将Message发送给Looper(Looper实在是太辛苦了)。 3.Handler可以在其他线程发送消息(那肯定,要不然要Handler干嘛,但要把Handler定义在全局变量上(不一定是Static变量))。 接着就是Handler发送消息了,其API有下面那么多
- post(Runnable)
- postAtTime(Runnable, long)
- postDelayed(Runnable, long)
- sendEmptyMessage(int)
- sendMessage(Message)
- sendMessageAtTime(Message, long)
- sendMessageDelayed(Message, long)
其实看起来那么多,但是也就两种,发送Runnable和发送Message,其实Runnable会包装进Message中,所以这样来看就只有一种Message而已。 包装的代码如下:
// 此方法用于向关联的MQ上发送Runnable对象,它的run方法将在handler关联的looper线程中执行
public final boolean post(Runnable r)
{
// 注意getPostMessage(r)将runnable封装成message
return sendMessageDelayed(getPostMessage(r), 0);//从这里可以看到
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain(); //得到空的message
m.callback = r; //将runnable设为message的callback,
return m;
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this; // message的target必须设为该handler!
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
处理数据
发送数据完了后肯定是开始处理数据了,处理数据主要有两个方法,dispatchMessage和handleMessage,其实dispatchMessage只是做过滤(过滤msg是Runnable还是Message),真正处理来时在handleMessage中。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg); //披着Message外壳的Runnable
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}