1.应用场景(什么情况下用到Handler机制)
倒计时(用Handler可以,并不是Handler机制)
网络请求(异步):
子线程获取数据交给主线程更新UI的时候,(子线程不能更新UI,如果更新,报错)
主线程不能直接网络请求
在后台执行耗时操作需要Service,
在Service中进行耗时操作,如果是HttpURLConnection则不行,需要自己new一个子线程,Retrofit和OKHttp可以,因为这两个里面自带异步,
同步和异步
1.2后台下载文件Service需要开启子线程进行网络请求下载文件,提示用户下载成功的时候,不能在子线程里面直接Toast,Handler发送消息给主线程直接在Service)
3.BroadcastReceiver(广播) 也是默认运行在主线程
Handler中重要的几个类:
Handler:
句柄 作用1:将子线程中的Message消息发送给主线程
作用2:可以将主线程Message消息发送到子线程
作用3:处理Message消息
Message:
消息对象,存储数据
Message msg= new Message(); 每次需要的时候就带创建对象,浪费资源
Message msg =handler.obtainMessage(); 消息池可以复用Message对象(比较节省资源)
MessageQueue:
(Activity任务栈,先进后出原则,)
先进先出原则
每个线程都有一个MessageQueue对象,主线程在创建的时候会默认创建一个MessageQueue对象, {子线程通过new的方式} 同时与之对应的还有个looper对象
Looper:
每一个线程都有一个Looper对象
作用:将MessageQueue里面的消息轮询出去交给Handler处理Looper.loop()死循环,会不停的从MessageQueue里面取消息,有消息就取出,没消息MessageQueue消息队列就处于阻塞状态,loop()就跳出死循环.
状态: 子线程获取Looper对象的话需要通过
Handler它是Android线程间通信工具类。
一般用于子线程向主线程发送消息,将子线程中执行结果通知主线程,从而在主线程中执行UI更新操作。
源码角度理解
Handler负责发送(sendMessage)和处理消息(handleMessage)
1)Message:消息载体,包含消息id(what)、消息处理对象(obj)、Runnable接口等。Handler发送一条消息后,会将该消息加入到MessageQueue统一消息处理队列中。
2)MessageQueue:消息队列。用来存放Handler发送的消息的队列,单链表实现
3)Looper:消息泵,通过Looper.loop( )创建一个死循环,不断地从MessageQueue中抽取Message,Message通过绑定的内部target(handler类型),msg.target.dispatchMessage(msg)将该消息传给对应的Handler接收。在dispatchMessage方法内调用handleCallback或handleMessage方法
ThreadLocal理解
创建Handler对象时,需要先为这个Handler创建Looper.prepara( )新建一个looper对象。一个线程中只会有一个looper。因为looper使用ThreadLocal.set方法。在set方法中,会对应着当前Thread,将Looper存储在其成员变量ThreadLocalMap中。其中key是ThreadLocal,value是looper。因此looper-threadLocal-Thread是一一对应关系。
实际上ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。
对象存放在哪里
在Java中,栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
Handler发送和处理消息过程分析
Handler发送消息:Handler.sendMessage(Message message)
Handler处理信息:
new Handler(){
// 通过复写handlerMessage()从而确定更新UI的操作
@Override
public void handleMessage(Message msg) {
...// 需执行的UI操作
}
};
sendMessage方法将message 入队messageQueue(单链表实现,接着说数据结构链表)在ActivityThread中会调用Looper.prepareMainLooper()生成looper,looper中会创建MessageQueue 。Looper.loop( )中有个死循环,不断从messageQueue中取message。
public static void main(String[] args) {
Looper.prepareMainLooper();
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper类
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static void loop() {
...// 仅贴出关键代码
// 1. 获取当前Looper的消息队列
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
if (msg == null) {
return;
}
// next():取出消息队列里的消息
// 若取出的消息为空,则线程阻塞
// 2.2 派发消息到对应的Handler
msg.target.dispatchMessage(msg);
// 把消息Message派发给消息对象msg的target属性
// target属性实际是1个handler对象
// 3. 释放消息占据的资源
msg.recycle();
}
}
Handler中的dispatchMessage方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler原理源码分析
/**
Handler:发送接收处理对象
Looper: 每一个线程只有一个looper.它是线程持有的looper中有一个Looper.loop()方法去读取MessageQueue中的消息,读出来之后会交给Handler来进行消息的处理
Message:是Handler接收和处理的对象,
MessageQueue:是用对应线程的Looper来创建和管理的
**/
Handler负责发送(sendMessage)和处理消息(handleMessage)
Message:消息载体,包含消息id(what)、消息处理对象(obj)、Runnable接口等。Handler发送一条消息后,会将该消息加入到MessageQueue统一消息处理队列中。
MessageQueue:消息队列。用来存放Handler发送的消息的队列,单链表实现
Looper:消息泵,通过Looper.loop( )创建一个死循环,不断地从MessageQueue中抽取Message,Message通过绑定的内部target(handler类型),msg.target.dispatchMessage(msg)将该消息传给对应的Handler接收。在dispatchMessage方法内调用handleCallback或handleMessage方法
原理流程:
首先子线程获取数据之后会通过Message.obtain()封装成Message对象,然后主线程创建好的Handler会将Message发送到主线程的MessageQueue中,在创建Handler的时候内部构造还会创建一个Looper对象,创建Looper对象的同时又会创建一个MessageQueue队列这个对象,Looper会通过Looper.Loop()方法会不断的轮询MessageQueue中的Message交给Handler处理
源码分析:
Handler源码
在创建Handler的时候,它构造内部会通过Looper.mylooper()创建一个Looper对象,除此之外,还会通过looper创建一个MessageQueue对象然后赋值给全局的MessageQueue对象,这样Handler和Looper就共用一个MessageQueue,这样这三者也就捆绑在一起了(如上图)
Handler源码
HandLer在发送消息的时候,不管是通过sendEmptyMessage()还是通过sendEmptyMessageDelayed()发送消息,最后消息都会走到enqueueMessage()方法中,这个enqueueMessage()方法其实就是将Handler发送的消息添加到MessageQueue消息队列中(如上图)
MessageQueue源码
而这个MessageQueue中主要包含,插入,读取和删除操作,在MessageQueue中有个enqueueMessage()方法,这个方法就是向MessageQueue中插入消息,而MessageQueue中会通过个next()方法获取下个Message,会被Looper.Loop()方法不停的取出Message对象,MessageQueue底层其实是通过单链表的数据结构来维护Message对象列表的(如上图)
Looper源码
public static void loop() {
...// 仅贴出关键代码
// 1. 获取当前Looper的消息队列
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next();
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
Handler源码中的dispathMessage()和HandleMessage()
MessageQueue是通过当前线程的Looper对象来管理和创建的,在Looper的构造中会创建个MessageQueue对象(如上图Looper源码),另外Looper中通过Prerare()方法来创建当前线程的Looper对象,在prepare()方法内部其实是通过ThreadLocal来保存和获取这个Looper对象的,ThreadLocal 不是 Thread,它是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,对数据存储后,只有在线程中才可以获取到存储的数据,对于其他线程来说是无法获取到数据。也就是说每个 Thread内可以通过ThreadLocal来创建变量的实例副本,且该副本只能由当前 Thread 可以使用,所以Threadlocal可以确保每个线程有唯一的一个Looper对象,Looper类中还有个loop()方法,其实内部是个死循环,在死循环内部通过queue.next()不停的从MessageQueue中轮询消息,如果没消息的话MessageQueue就处于阻塞状态,但是对当前主线程没影响,轮询出来消息之后会将Message交给Handler中的dispatchMessage()来处理,最后把Message交给在dispatchMessage()中的HandleMessage来处理。