基本概述
在Android开发中提到消息机制应该所有人都不陌生,但是估计也很少有人能把消息机制详细地说出个所以然来,我们在开发过程中,有很多技术痛点,就是明明很多时候我们在用的东西,我们却不知道是为什么,它具体是个什么东西,很多时候我们只在乎它如何被拿来用,而不去关心更深层次的东西,也许这就是初中级向上进阶的阻碍吧。还好,我意识到了这一点,尽力去了解更多事实的真相…一不小心说了这么多废话,言归正传吧。
在Android中,我们提到的消息机制常常指的就是Handler机制,Handler是Android中的上层接口,在开发的过程中,我们可以利用Handler将一件事情切换到Handler所在的线程中去执行(好好理解这句话)。为什么会有这样的机制出现?我们来考虑一下,在实际的操作中,我们发现,Handler机制的运用主要是在UI更新上,当我们需要做一个耗时操作时,我们不可能在mainThread中做这个事情,因为ANR的存在,这时我们需要开启一个新的线程去做这个事情,当事件完成后再通过Handler去告诉mainThread现在可以更新UI了。这就是对消息机制的一个很宽泛的描述。这时候,我们应该考虑一个问题?为什么我们不干脆在开启的新线程中更新UI呢,应该很多人会说是因为Android不允许这样做?那么, 为什么不允许呢?
如果不限制UI的更新规则(即可在任何线程中操作UI)会带来什么样的坏处?如果所有线程都可以改变UI,那我们如何保证UI朝着我们预期的方向发展?这就像是共享内存一样,同时的操作会让UI的状态变得不可预期。那么,如果加上锁机制呢?这样必定会大大降低UI的访问效率,因为锁机制会阻塞线程,就会让我们的应用在很多情况下看起来像失了智一样,卡顿严重,所以Handler机制油然而生了。
工作原理
Android的Handler机制它的工作原理是怎样的呢?我们在线程中创建一个Handler对象,当使用它的时候会发现系统会报这样的错:
can not create handler inside thread that has not called Looper.prepare();
它描述了在一个线程中我们不能在没有Looper的前提下去使用Handler,也就是说Handler机制的实现需要Looper这个东西,那么Looper是啥呢?我们可以通过Looper.prepare()在当前线程中创建一个Looper对象,当我们查阅源码的时候可以发现,Looper.prepare()做了什么,实际上它创建了一个MessageQueue(消息队列)。Looper相关源码如下:
public static void prepare(){
prepare(true);
}
public static void prepare(boolean quitAllowed){
if( sThreadLocal.get()!=null ){
...
}
sThreadLocal.set(new Looper(quitAllowed));
}
public Looper(){
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在创建了Looper之后,我们不仅仅得到了looper对象,还得到了一个消息队列messageQueue,这时候才构建了一个完整的H