转载请注明出自flowsky37的博客,尊重他人辛苦劳动!
在android开发中,Handler太熟悉了,处处可见。确实挺好用的。它可以轻松的将任务切换到Handler所在的线程中去执行。如下面代码:
//发送message
MyHandler myHandler = new MyHandler(this);
//业务逻辑
...
Message message = new Message();
message.what = 0x001;
myHandler.sendMessage(message);
//接收message
public class MyHandler extends Handler {
private Context context;
public MyHandler(Context context) {
this.context = context;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0x001:
//业务逻辑
//...
Toast.makeText(context,"收到messge",Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
break;
}
}
}
so easy,对吧!很多人认为Handler的作用是更新UI,这没问题。但是更新UI只是Handler的一个特殊使用场景。具体来讲,所有比较耗时的操作一般都是在子线程中完成,否则容易引起ANR,如读写文件、数据插入、网络请求等,完成后需要对UI进行修改的,但是由于android开发规范限制,子线程不能更新UI。所以这时候通过Handler将更新UI的操作切换到主线程中执行。通俗的讲,Handler不是为了UI而生,只是常被大家用来更新UI。Handler的主要作用应该是将一个任务切换到某个指定的线程中去执行。
Android的消息机制主要是指Handler运行机制,关于Handler运行机制,我们不得不提到其底层的MessageQueue与Looper。其关系大概如下图:
没看懂?没关系,后面会更详细的。先说一下MessageQueue与Looper是啥呢!
MessageQueue:消息队列,它内部存储了一组消息,以队列的形式对外提供插入和删除的工作。内部结构不是真正的队列,而是采用单链表的数据结构来存储消息列表。
Looper:可以理解为消息循环。MessageQueue 只是一个消息的存储单元,它不能去处理消息,Looper 填补了这个功能,Looper 会以无限循环的模式去查看Message中是否有新消息,否则就一直等待。
重点:如果需要使用Handler就必须为当前线程创建一个Looper,因为线程默认是没有Looper的。如果线程中没有Looper的话,会抛出异常的。我我们可以一起看看一下Handler的构造源码,它有好几个构造函数:
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
无参数的,接着往下看:
/**
* Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle messages.
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler(Callback callback) {
this(callback, false);
}
还有好几个其它的构造方法,可自行阅读源码。这两个构造方法都指向了this(callback, false),我们接着看this(callback, false)的具体实现:
public Handler(Callback callback, boolean async) {
...
//获取当前线程的looper对象
mLooper = Looper.myLooper();
//判断Looper是否为null
if (mLooper == null) {
//如果为null则报异常
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
通过源码可以看出,在创建Handler实例的时候,先会通过Looper.myLooper()去获取当前线程的Looper,然后判断looper是否为null。如果为null,会提示通过Looper.prepare()去创建。
我们接着看下Looper.prepare()的源码:
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
prepare()是一个空构造函数,其内部是调用了prepare(true),我们接着看prepare(true):
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
最后一行代码很很清楚的显示了创建了一个Loope