Handler原理

概述

很多android初学者对android 中的handler不是很明白,其实Google参考了Windows的消息处理机制,

在Android系统中实现了一套类似的消息处理机制。在下面介绍handler机制前,首先得了解以下几个概念:

####1. Message

 消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。

####2. Message Queue

 消息队列,用来存放通过Handler发布的消息,按照先进先出执行。

####3. Handler

 Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。

####4. Looper

 循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。

####5. 线程

 UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。

每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。


image.png

好了,下面是正文~

Handler作用:

因为在Android中,主线程不建议做耗时的操作,子线程不建议跟新UI,但是Android开发,其实就是搭建好页面,将服务器的数据展示到页面上,所以我网络请求使用会非常频繁,而网络请求属于耗时操作,需要放到子线程完成,但一般情况下也不会通过子线程更新UI,需要将请求成功的数据发送到主线程进行UI更新,所以一般会使用到handler。

Handler执行流程:

首先handler作为任务执行者,一般创建在主线程,当子线程有需要发送的数据,通过创建message对象,使用handler对象将消息发送到messagequeue,messagequeue遵循了队列先进先出的原则,当主线程的looper循环消息的时候,会按照messagequeue队列的顺序循环消息,并将消息给到任务执行者handler去执行任务。

Handler执行原理:

Handler创建完成后,内部的Looper以及MessageQueue就可以和Handler一起协同工作,然后通过Hadler的post方法将一个Runnable投递到Handler内部的Looper中去处理,也可以通过Handler的send方法发送一个消息,这个消息会在Looper中做处理。Post最终也是通过send来完成的。当Handler的send方法被调用时,他会调用MessageQueue的enqueueMessage方法将这个消息放入消息队列中,然后Looper发现有新消息到来时,就会处理这个消息,最终消息中的Runnable或者Handler的handlerMessage方法就会被调用。Looper试运行在Handler所在的线程,所以就把业务逻辑切换到主线程了

1.ThreadLocal的工作原理

(1)定义:ThreadLocal是线程内部的数据存储类,通过他可以在指定的线程中存储数据,该数据只有在指定线程中可以获取
(2)使用场景:当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候另外还可以使用在复杂逻辑下的对象传递,比如监听器的传递
ThreadLoal的值在table数组中的存储位置总是为ThreadLocal的reference字段所标识的对象的下一个位置。ThreasdLoacal的set和get方法所操作的对象都是当前线程的localValues对象的table数组,因此在不同的线程中访问同一个ThreadLocal的set和get方法,他们对ThreadLocal所做的读写操作仅限于各自线程的内部,从而实现在多个线程中互不干扰的存储和修改数据。

Looper的工作原理
Looper在Android的消息机制中扮演着消息循环的角色,就是不停的从MessageQueue中查看是否有新消息,如果有消息就立刻处理,否则就一直阻塞在哪里首先在构造方法中创建一个MessageQueue即队列消息,然后将当前的对象保存起来Looper除了prepare方法外,还提供了prepareMainLooper方法,这个方法主要是给主线程也就是ActivityThread创建Looper使用的,其本质也是通过prepare方法来实现的。由于主线程的Looper比较特殊,所以Looper提供了一个getMainLooper方法,通过它可以再任何地方获取到主线程的Looper。Looper也是可以退出的,Looper提供了quit和quitSafely来退出一个Looper,二者的区别是:quit会直接退出Looper,而quieSafely只是假定一个特殊标记,然后把消息队列中的已有消息处理完毕后才安全退出。Looper退出后,通过Handler发送消息失败,这个时候Handler的send方法会返回false。在子线程中,如果手动为其创建Looper,那么在所有的事情完成以后应该调用quit方法来终止消息循环,否则这个子线程就会一直处于等待状态,而如果想退出Looper以后,这个线程就会立刻终止,,因此建议不需要的时候终止Looperloop方法是个死循环,唯一跳出循环的方式是MessageQueue的next方法返回null。当Looper的quit方法被调用时,Looper就会调用MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,它的next方法就返回null。Loop必须退出,否则loop循环就会无限循环下去。loop方法会调用MessageQueue的next方法,而next方法是一个当没有消息时 是一个阻塞线程,便会导致Looper也会阻塞在那里。当MessageQueue的next方法返回了新的消息,Looper就会处理这条消息:msg.target.disapatchMessage,这里msg.target是发送这条消息的Handler对象,消息交给dispatchMessage方法来处理。而这个dispatchMessage方法是在创建Handler时所用的Looper中执行。这样就把代码逻辑切换到主线程。

handler,looper和Measge之间的如何协作的

image.png

主线程向子线程发送消息:

首先handler肯定是要创建到子线程当中,用于接收主线程发来消息进行处理,但是,因为子线程没有looper对象,首先需要调用looper.prepare(),当主线程发来消息后,已经准备好的looper同样会去消息队列当中循环消息,交给handler,但handler真正能够使用该数据还得调用looper.loop();

Measge可以通过wait来区分消息
Mesage通过takte来区分handler

你可能感兴趣的:(Handler原理)