Handler
Android
开发过程中,易用于线程间通信
Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。
为什么要用Handler?
Android 中的一些耗时操作需要在子线程中去完成,Android 又规定访问 UI 只能在主线程中进行,在子线程中访问 UI,程序就会抛出异常。系统提供 Handler 就是为了解决在子线程中无法访问 UI 的矛盾。
常见的耗时操作有(网络请求,文件的读写,数据读写,复杂逻辑及算法等);
Handler主要分为以下几个类
ActivityThread:程序的入口调用main方法(有且只有一个)
Handle:发送消息和接收消息
handler必须创建looper,但是主线程的handler不需要显示创建;
可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
handler.sendMessage(msg);
handler.sendEmptyMessage();
handler.sendEmptyMessageAtTime();
handler.sendEmptyMessageDelayed();
handler.sendMessageAtTime();
handler.sendMessageDelayed();
handler.sendEmptyMessageDelayed();
都会走下面这个方法
然后进入以下方法
只有这个方法直接跳过上面的方法直接进入
handler.sendMessageAtFrontOfQueue();
点击访问enqueueMessage
进入可以看到
Message:消息本身的对象(即任务/事件)
MessageQueue:存储message的数据结构容器(消息队列)
用来存放线程放入的消息。 messagequeue在looper构造方法里创建,每一个looper维护一个messagequeue,每个线程维护独立的messagequeue;
Looper:从容器中获取message,并转发给相应线程的handler
looper独立于线程,每个线程维护一个独立的looper;
一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
ThreadLocal:用于保存本地线程变量,对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。.
threadlocal类非诚重要,独立于线程,每个线程的threadlocal对象互不干扰
- ThreadLocal.get: 获取ThreadLocal中当前线程变量的值。
- ThreadLocal.set: 设置ThreadLocal中当前线程变量的值。
- ThreadLocal.remove: 移除ThreadLocal中当前线程变量的值。
- ThreadLocal.initialValue: ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值。
HandlerThread:本质上就是一个普通Thread,只不过内部建立了Looper
- 创建一个HandlerThread
mThread = new HandlerThread("handler_thread");
- 启动一个HandlerThread
mThread.start();
- 退出循环
Looper是通过调用loop方法驱动着消息循环的进行: 从MessageQueue中阻塞式地取出一个消息,然后让Handler处理该消息,周而复始,loop方法是个死循环方法。
mHandler.quit();
HandlerThread的特点
- HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。
- 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。
- 但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。
- HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
- 对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。
为什么Handler不会产生ANR
handler
采用链表方式存储消息 nativeWake(系统唤醒机制调用底层c)有消息就唤醒,没有消息就休眠。所以handler不会产生ANR
Handler创建消息
每一个消息都需要被指定的Handler
处理,通过Handler
创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler
创建消息时首先查询消息池中是否有消息存在,如果有直接从消息池中取得,如果没有则重新初始化一个消息实例。使用消息池的好处是:消息不被使用时,并不作为垃圾回收,而是放入消息池,可供下次Handler
创建消息时使用。消息池提高了消息对象的复用,减少系统垃圾回收的次数。
Handler发送消息
UI主线程初始化第一个Handler
时会通过ThreadLocal
创建一个Looper
,该Looper与UI主线程一一对应。使用ThreadLocal
的目的是保证每一个线程只创建唯一一个。之后其他Handler初始化的时候直接获取第一个Handler
创建的Looper
。Looper
初始化的时候会创建一个消息队列MessageQueue
。至此,主线程、消息循环、消息队列之间的关系是1:1:1。
Handler处理消息
UI主线程通过Looper
循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler
,然后将消息分发到指定的Handler
进行处理
Ps:仅仅是个人在了解handle的时候一些简单记录。