这段时间准备面试,重新将Handler的消息传递机制回顾了一遍,解决了原先认识的一些盲点。
首先来讲讲背景,我们为什么要使用Handler。由于Android 是强交互的移动操作系统,用户交互必不可少,界面反馈显示需要更新UI,但如果每个线程都能随意更新UI,那么多个线程同时进行操作时,最终UI的状态是不可知的,也就是说会有线程安全问题,于是乎Android中规定:只有主线程能操作UI,因此主线程也叫UI线程。
早期的Android 版本,界面经常会出现卡顿的现象,时不时抛应用程序无响应(ANR)异常,因为我们的UI线程可能做了一些耗时的操作,比如文件读取,网络访问等。为了使UI线程保持比较快的响应速度,耗时操作不能在主线程中进行。但很多时候执行完任务需要反馈结果到界面又需要进行UI操作,这就跟我们只有UI线程能更新UI的规定相冲突了。那么怎么来解决这个矛盾呢?
没错,就是通过我们今天要讲的Handler消息传递机制。很多人认为Handler只是用来更新UI的,确实可以,但这么理解难免有些狭隘,我的理解是这样的:Handler是用来将任务切换到不同线程中执行的机制。
================================================================
一、Handler的使用
我们日常开发中,用法通常是new 一个Handler对象,或者派生一个内部类来得到Handler,然后重写里面的handleMessage()方法,然后在子线程中拿着我们的handler.sendMessage()方法,将信息Message发送给主线程去处理,使用起来非常简单。符合我们面向对象开发的 最少知识原则。
二、Handler的原理
其实Handler能实现这么强大的功能,离不开背后Looper, MessQueue的默默支撑。之所以是默默支持,是因为我们主线程已经帮我们做了初始化,当然有些朋友说写了那么久的Android从来没见过main方法,其实也是主线程ActivityThread中帮我们实现了。
public static void main(String[] args){
..
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attch(false);
if(sMainThreadHandler == null){
sMainThreadHandler = thread.getHandler();
}
...
Looper.loop();
}
主线程的消息循环开始了以后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是ActivityThread.H,它内部定义了一组消息类型,主要包含了四大组件的的启动和停止等过程。
ActivityThread通过ApplicationThread和ActivityManagerService(AMS)进行进程间通信,AMS以进程间通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到主线程ActivityThread中执行,这个过程就是主线程的消息循环模型。
三、Looper, MessageQueue, Message, Handler之间的关系
Looper轮询器的构造方法如下:
private Looper(boolean quitAllowed){
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Handler的构造方法如下:
public Handler(Callback callback,boolean async){
mLooper =Looper.myLooper();
mQueue = mLooper.mQueue;
mCallback = callback;
}
从上面的构造方法可以看出,Handler通过Loop和消息队列MessageQueue进行一一绑定,而Looper又是通过ThreadLocal实现了线程隔离,也就是说每个线程最多只会只会得到自己的Looper。
static final ThreadLocal<Looper> dThreadLocal = new ThreadLocal<Looper>();
public static void prepare(){
prepare(true);
}
public static void prepare(boolean quitAllowed){
if(sThreadLocal.get() != null){
throw new RuntimeException("Only one Looper maybe created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static Looper myLooper(){
return sThreadLocal.get();
}
调用Looper.loop()后,开始轮询,loop方法中又会调用MessageQuene中的next()方法,当有队列中有消息时,就会取出来到Looper中,通过msg.target.dispatchMessage()方法进行分发,(msg.target 即消息的发送者handler)
public void dispatchMessage(Message msg){
if(msg.callback != null){
handleCallback(msg);
}else{
if(mCallback != null){
if(mCallback.handleMessage(msg){
return;
}
}
handleMessage(msg);
}
}
随后就来到我们重写的handleMessage()中来了。
。。。
好懊恼,部分草稿忘记保存,第一篇先到这里吧
MessageQueue里面还有一个非常有意思的东西叫dleHandler,工作换了后面估计没机会更了,放在草稿箱也不是事,当抛砖引玉吧,开启传送门:https://mp.weixin.qq.com/s/KpeBqIEYeOzt_frANoGuSg?