消息机制概述
Android 系统在设计的初期就已经考虑到了 UI 的更新问题,由于 Android 中的 View 是线程不安全的,然而程序中异步处理任务结束后更新 UI 元素也是必须的。这就造成了一个矛盾,最简单的解决方法肯定是给 View 加同步锁使其变成线程安全的。这样做不是不可以,只是会有两点坏处:
1 加锁会有导致效率底下
2 由于可以在多个地方更新 UI,开发就必须很小心操作,开发起来就很麻烦,一不小心就出错了。
基于以上两个缺点,这种方式被抛弃。于是,设置一个线程专门处理 UI控件的更新,如果其他线程也需要对 UI 进行更新,不好意思,您把您想做的告诉那个专门处理 UI 线程的家伙,让它帮你做。大家各有各的任务,井水不犯河水,各司其职,效率才会高,
那么您也看出来了,消息机制其实可以很简单的用一句话概括,就是:其他线程通过给特定线程发送消息,将某项专职的工作,交给这个特定的线程去做。比如说其他线程都把处理 UI 显示的工作通过发送消息交给 UI 线程去做。
消息机制相关类
消息主要设计到下面几个类:
Handler:这是消息的发出的地方,也是消息处理的地方。
Looper:这是检测消息的地方。
MessageQueue: 这是存放消息的地方,Handler 把消息发到了这里,Looper 从这里取出消息交给 Handler 进行处理
Message:呜呜呜…他们发的是我,处理的也是我。
Thread:我在这里专门指代的是,处理消息的线程。消息的发送是在别的线程。
源码跟踪--梳理消息发送接收过程
咱们先来走一个在子线程想要更新UI的流程:
1 在主线程新建一个 Handler 对象,在构造方法中传入一个实现 Handler.Callback 接口的匿名类的对象,实现接口中的 handleMessage 方法
2 在非 UI 线程使用 Handler 的 sendMessage 或者 post 方法发送一个消息
3 然后 handleMessage 方法会在不久的将来马上执行,实现更新 UI 的操作。
关于类Handler:
Handler 拥有 Looper 的引用,通过得到 Looper 对象获得 Looper 中保存的 MessageQueue 对象
Handler 拥有 MessageQueue 的引用,使 Handler 得以拥有发送消息(将 Message 放入 MessageQueue )的能力
Handler 拥有 Handler.Callback 的引用,使得 Handler 可以方便的进行消息的处理。
根据上面的1 2 3 步,我们跟进源码看看:
1 创建handler handler构造方法源码在handler中获取了mLooper,mQueue对象,主要看mLooper是怎么获取的,Looper.myLooper();再跟进这个方法:
Looper类可以看到是由ThreadLocal维护的,我们知道ThreadLocal可以保存对应线程的变量,那么必定保存了当前线程的Looper。我们查找ThreadLocal.set()方法:
Looper类方法可以看到是在调用Looper.prepare()时设置的,在主线程中是谁调用Looper.prepare()的呢?没错,就是ActivityThread(主线程),在创建主线程的main方法里调用:
ActivityThread中的main方法那么就可以确定,上面ThreadLocal存储的Looper就是主线程的Looper。mQueue自然也是主线程的Looper的变量。然后就看发消息了,看看 Handler.sendMessage 干了啥,
handler类发送消息可以看到,Handler类中发送消息最后调用了MessageQueue的enqueueMessage()方法,并且把msg.target设置成了handler本身,这在之后分析中用到,继续跟进:
MessageQueue类方法到这里,我们发现handler已经成功法一个消息放到了主线程的MessageQueue中了,接下来就是取消息操作了。只要主线程中调用了Looper.loop()方法,那就启动了一个死循环,会从MessageQueue中不停的取消息(无消息就阻塞)。
Looper的loop方法可以看到,loop()方法开启了一个死循环,不断从MessageQueue取消息,并调用msg.target(Handler)去调用dispatchMessage(msg)方法。那就是调用了handler的dispatchMessage(msg)方法
handler类方法这里分三种情况,
* 如果Message中callback对象不为空(这是调用handler.post(Runnable)方法发送的消息),就调用callback的run方法
* 否则如果创建Handler的时候如果设置了Callback就调用创建时候的传入的实现Handler.Callback接口的类的对象的handleMessage方法,看这就是回调方法被调用的地方。
* 再如果没有mCallback对象,就调用自身的handleMessage方法,为了Handler的子类复写了该方法的时候,方便调用,如,IntentService里的ServiceHandler就是继承自Handler的,并且重写了handleMessage方法。
我们创建handler时实现了Handler.Callback接口,所以就跳到一开始创建handler的地方处理消息啦。
小结
ok,再整理一下思路:1 在主线程创建handler实现Handler.Callback接口,主线程一运行就存在Loop和MessageQueue。2 其他线程通过主线程的该handler发送msg,发送到了主线程的MessageQueue。3 主线程的Looper从MessageQueue循环取消息,取到该消息就调用msg.target(handler).dispatchMessage(msg),也就跟着调用了handler的handleMessage()。
另外,如果非主线程要创建handler对象,必须要调用Looper.prepare()创建一个Looper和Looper.loop()开启消息循环。
网友评论