前言
什么叫又熟悉又陌生,这些概念就是了。对于这些概念相信没有人没见过,但是又没有几个人真正熟悉,所以就一直朦朦胧胧恍恍惚惚凄凄惨惨戚戚。今天就来解决这些恩恩怨怨,做个了断。
概念初探
Runnable,Message,MessageQueue,Looper和Handler的关系简图.png上面是Runnable,Message,MessageQueue,Looper和Handler的关系简图。其中:
- Runnable和Message可以被压入某个MsaageQueue中,形成一个集合。注意:一般情况下某种类型的MsaageQueue只允许保存相同类型的Object。上图中我们只是为了方便叙述才把它们混放在MessageQueue中,实际源码中需要先对Runnable进行相应转换。
- Looper循环地去做某件事
它不断地从MessageQueue中取出一个item,然后传给Handler进行处理。如此循环往复,假如队列为空,那么它会进入休眠。 - Handle是真正“处理事情"的地方
它利用自身的处理机制,对传入的各种Object进行相应的处理并产生最终结果。
用一句话来概括它们,就是:
Looper不断获取MessageQueue中的一个Message,然后由Handle来处理。
1. Handler
不知道有没有人注意过,Handle和线程Thread是什么关系。
public class Handler {...
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
}
从Handler的源码中看不出与Thread有什么关系,但其实:
- 每个Thread只对应一个Looper;
- 每个 Looper只对应一个MessageQueue;
- 每个MessageQueue中有N个Message;
- 每个Message中最多指定一个Handler来处理事件。
5.一个Thread可以对应多个Handler。
Handler是应用开发人员经常会使用到的一个类,它有两个方面的作用。
- 处理Message,这是它作为"处理者"的本职所在。
- 将某个Message压入MessageQueue中。
#实现第一个功能的相应函数
public void dispatchMessage (Message msg); //对Message进行分发
public void handleMessage(Message msg); //对Message进行处理
Looper从MessageQueue中取出一个Message后,首先使用调用dispatchMessage进行消息派发;后者则根据具体的策略来将Message分发给相应的负责人。默认情况下Handler的派发历程是:
Message.callback(Runnable 对象)是否为空
在不为空的情况下,将优先通过callback来处理
Handler.mCallback是否为空
在不为空的情况下,调用mCallback.handleMessage
如果前两个对象都不存在,才调用Handler.handleMessage
由此可见,Handler的扩展子类可以通过重载dispatchMessage或者HandleMessage来改变它的默认行为。
Handler的第二个功能,容易引起开发人员的疑惑,因为这样形成了Handler->MessageQueue->Message->Handler的循环。
#实现第二个功能的主要方法
1. post系列
final boolean post (Runnable r);
final boolean postAtTime(Runnable r, long uptimeMills);
2. Send系列
final boolean sendEmptyMessage(int what);
final boolean sendMessageAtFrontOfQueue(Message msg);
boolean sendMessageAtTime(Message msg, long uptimeMillis);
Post和Send的作用都是将某一个消息压入MessageQueue中,区别在于后者处理的参数直接就是Message,而Post需要先将零散的信息转换成Message,再调用Send系列函数来执行下一步。
#post方法内部
public final boolean post(Runable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r){
Meaage m = Message.obtain();
/*
Android系统会维护一个全局的Message池。当用户需要时可以通过obtain函数获得,避免产生不必要的资源浪费。
*/
m.callback = r;/*将Runnable对象设置为Message的回调函数*/
return m;
}
有上述源代码可以看出,post实质上是根据传入的信息,从Mseeage池中获得一个Message并将Runbale设置为Message的回调函数。最后还是使用send函数将Message添加到MessageQueue。
2. MessageQueue
MessageQueue是一个消息队列,因而它具有队列的所有常规操作,包括:
- 新建队列
由其构造函数和本地方法nativeInit组成。其中nativeInit会在本地创建一个NativeMessageQueue对象,然后直接赋值给MessageQueue中的成员变量。这一系列操作实际都是通过内存指针进行的。 - 元素入队
final boolean enqueueMessage(Message msg, long when) - 元素出队
final Message next() - 删除元素
final void removeMessage(Handle h, int what, Object object)
final void removeMessage(Handler h, Runnable r, Object object) - 销毁队列
和创建过程一样,还是通过本地的NativeDestory来销毁一个MessageQueue。
3. Looper
Looper有点类似于发动机,它的推动使得整个Handler机制成为活源之水,不断的处理新的消息。Looper的使用有两种情况,即在主线程以及在工作线程。
#工作线程的使用Looper的范例。
class LooperThread extend Thread{
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg){
//处理消息的方法
}
};
looper.loop();//进入主循环
}
}
这段代码概括起来只有三个步骤:
- Looper的准备工作(prepare)
- 创建处理消息的Handler
- Looper开始运作(loop)
我们可以看到使用的步骤十分简单,但是仍有一些地方十分模糊,例如:looper是如何创建的,loop是如何与handler还有MeaasgeQueue进行连接的。
首先我们发现在上述调用中使用了Looper.prepare()函数,既然要用Looper类的函数,那么LooperThread中肯定就得import android.os.Looper;观察Looper类我们发现在Looper类里有一个很重要的成员
static final ThreadLocal<Looper> sThreadLoal = new ThreadLocal <Looper> ();
这是一个静态变量,这就意味着在引用Looper时,sThreadLocal时就已经存在并成功构建。ThreadLocal对象是一种特殊的全局变量,但是这种全局只局限与线程内,这就意味着每个线程的Looper都是独立的。Looper为我们提供了很多静态方法,可这毕竟是公共的方法,其内部还需要有针对每个Thread的特定存储空间。因而sThreadLocal肯定会创建一个只针对当前线程的Looper以及其他相关的对象,而且这个操作很可能在prepare()。
private static void prepare(boolean quitAllowed){
if(sThreadLocal.get() != null){
throw new RuntimeException("Only one Looper may be created per thread")
}//这个判断保证一个线程中只有一个Looper实例。
sThreadLocal.set(new Looper(quitAllowed));
}
由上述代码我们可以看出,sThreadLocal存储了一个Looper对象。
接下来创建一个Handler对象,这个步骤看起来也是平淡无奇,就是使用Handler的构造函数创建一个实例。那么,Handler到底与Looper是如何连接起来的呢?没错就是构造函数。
Handler有很多构造函数:
public Handler();
public Handler(Callback callback);
public Handler(Looper looper);
public Handler(Looper looper, Callback callback);
之所以会有那么多参数,是因为Handler中有很多内部变量需要初始化
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
以第一个无参构造函数为例:
public Handler(){
/*省略部分代码*/
mLooper = Looper.myLooper();//还是通过sThreadLocal.get()来获取当前线程中的实例。
...
mQueue = mLooper.mQueue;//mQueue是Looper与Handler之间沟通的桥梁
mCallback = null;
}
这样Handler和Looper,MessageQueue就联系起来了。后续Handler执行Post/Send两个操作时,会将消息投递到mQueue也就是mLooper.mQueue中,一旦Looper处理到这一消息,它又会从中调出Handler进行处理。
好了就剩下Looper.loop()了,这部分需要借助ActivityThread讲解。看到这里一定有一点累了,喝口小茶,歇息几分钟,下一篇再仔细说明。
网友评论