学习总结Handler机制原理

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();

都会走下面这个方法


image.png

然后进入以下方法


image.png

只有这个方法直接跳过上面的方法直接进入

handler.sendMessageAtFrontOfQueue();
image.png

点击访问enqueueMessage进入可以看到

image.png

Message:消息本身的对象(即任务/事件)

MessageQueue:存储message的数据结构容器(消息队列)

用来存放线程放入的消息。 messagequeue在looper构造方法里创建,每一个looper维护一个messagequeue,每个线程维护独立的messagequeue;

image.png

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();
image.png
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创建的LooperLooper初始化的时候会创建一个消息队列MessageQueue。至此,主线程、消息循环、消息队列之间的关系是1:1:1。

Handler处理消息

UI主线程通过Looper循环查询消息队列UI_MQ,当发现有消息存在时会将消息从消息队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理
Ps:仅仅是个人在了解handle的时候一些简单记录。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。