android消息机制
- android的消息处理机制也就是指handler的运行机制,使用handler可以很简单的将一个任务切换到handler所在的线程中去执行
- handler的运行需要配合looper和MessageQueue一起使用,消息队列用来存储接收到的消息,looper用来管理消息队列,在主线程中,当主线程被创建的时候,就会初始化looper
- handler创建的时候是会采用当前线程的looper类构建消息循环系统的,而如何获取looper是需要通过threadLocal来获取的,threadLocal保存了每个线程中的数据,它可以互不干扰的为各个线程存储并提供数据
- 线程是默认没有looper的,要使用handler必须为线程创建looper,而UI线程在创建时就会初始化一个looper
handler的主要作用
- 将一个任务切换到handler所在线程中去执行
子线程不能访问UI的原因
- UI空间不是线程安全的,多线程中并发访问会导致UI控件处于不可预期的状态
为什么不加锁了的原因:
- 加上锁会影响访问的效率
- 会让UI访问的逻辑更加的复杂
handler工作过程
handler创建之前必须先有looper,创建完之后,handler通过post方法将Runnable投递到Handler内部的looper中去处理,还可以通过send方法发送一条message(post方法最终也是通过send方法来完成的),当send方法被调用是,它会调用messageQueue中的enqueueMessage方法将消息放入到队列中去,然后looper发现有消息来了,就会处理这个消息,最后消息中的Runnable或者handMessage方法就会被调用
Threadlocal的工作原理
threadLocal是线程内部的数据存储类,可以在指定的线程中存储数据,然后就可以在指定的线程中获取到指定的数据,对于其他线程是无法获取到的
用处:一般是在以线程为作用域并且在不同线程有不同数据副本的情况下考虑使用ThreadLocal,另一个使用场景是:复杂逻辑对象的传递
- ThreadLocal是一个泛型类,可以通过get,set方法来设置获取数据
消息队列的工作原理
消息队列也就是MessageQueue,主要包含插入和删除两个操作,对应着enqueueMessage方法和next方法,消息队列内部实际上是一个单链表的形式而不是队列,在next方法中,里面有个无限循环,如果消息队列中没有消息,就会一直阻塞在这里
looper工作原理
handler需要looper,没有looper就会出错,在一个线程内创建looper使用looper.prepare()方法,接着通过Looper.loop()来开启消息循环
looper为主线程提供了prepareMainLooper方法,为主线程创建Looper使用的,本质也是prepare方法来实现的,通过getMainLooper方法可以获取到主线程的looper
looper可以退出的,使用quit,quitSafely可以退出一个looper,区别是quit是直接退出,quitSafely是设定一个退出标记,待消息队列中的已有消息处理完毕后才会安全的退出
在子线程中,如果手动为其创建了looper,那么在消息处理完之后一定要退出looper,不然会使子线程一直处于等待的状态,而退出looper之后,子线程就会终止
loop方法调用了之后消息循环系统才会真正的启动起来,loop方法是一个死循环,唯一跳出循环的方式是MessageQueue的next方法返回一个null,在looper的quit或者quitSafely方法调用后,就会调用messageQueue的quit或quitSafely方法通知消息队列退出,当消息队列标为退出状态,它的next方法就会返回null
handler工作原理
主要工作:消息的发送和接收
工作过程: 向消息队列插入一条消息,MessageQueue的next方法将消息返回给looper,looper将消息交由handler处理,即handler的dispatchMessage方法会被调用
dispatchMessage方法实现:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
解释:先检查message的callback是否为null,不为空就交由handleCallback来处理,callback就是一个Runnable对象,实际上就是post方法中方法所传递的Runnable参数,其次检查mCallback是否为空,不为null就调用他的handleMessage方法,mCallback是一个接口
通过Callback接口可以创建一个不需要继承handler的handler对象:Handler handler = new Handler(callback);
Handler特殊构造方法:通过一个指定的looper来构造handler
public Handler(Looper looper) {
this(looper, null, false);
}
主线程的消息循环机制
activity的主线程就是ActivityThread,主线程的入口方法是main方法,在main方法中系统会通过Looper.prepareMainLooper()来创建主线程的Looper以及消息队列,通过Looper.loop()方法来开启主线程的消息循环
主线程的handler就是ActivityThread.H,它的内部机制定义了一组消息类型,包含了四大组件自动和停止等过程
主线程Handler过程: activityThread通过ApplicationThread和AMS进行进程间的通信,AMS以进程间的通信完成ActivityThread的请求后会回调Binder方法,然后ApplicationThread会向H发送消息,H接收到消息后将任务切换到ActivityThread中去执行。