小木箱生长营并发编程系列教程(排期中):

并发编程 根底篇(上) android线程那些事

并发编程 根底篇(下) android线程池那些事

并发编程 进步篇(上) Java并发关键字那些事

并发编程 进步篇(下) Java锁安全性那些事

并发编程 高档篇(上) Java内存模型那些事

并发编程 高档篇(下) Java并发BATJ面试之谈

并发编程 实战篇 android下载器完成

Tips: 关注微信大众号小木箱生长营,回复Handler可取得Handler免费思想导图

一、序言

Hello,我是小木箱,欢迎来到小木箱生长营并发编程系列教程,今日将共享并发编程 根底篇(中) 三大剖析法剖析Handler

三大剖析法剖析Handler首要分为三部分,榜首部分是5W2H剖析Handler,第二部分是MECE剖析Handler,第三部分是SCQA剖析Handler。

首要,5W2H剖析Handler针对Handler提出了六个高价值问题。

然后,MECE剖析Handler分为两部分,榜首部分是Handler常见API,第二部分是Handler音讯机制。

终究,SCQA剖析Handler,还原企业面试现场,使用B站渠道,以SCQA形式回答33个Handler高频面试题。

其间,Handler音讯机制首要分为三部分,榜首部分是Handler发送Message,第二部分是Looper轮询读取,第三部分是Handler收回Message。

并发编程   基础篇(中)   三大分析法分析Handler

假如学完小木箱的三大剖析法剖析Handler,那么任何人都能经过android Handler相关技能面试。

二、5W2H剖析Handler

5W2H又叫七何剖析法,5W2H是二战的时分,美国陆军武器修理部创造的思想办法论,便于启发性的了解深水区常识。

5W2H是What、Who、Why、Where、When、How much、How首字母缩写之和,广泛用于企业技能管理、脑筋风暴等。

今日小木箱尝试用5W2H剖析法剖析Handler。

2.1 What: 怎么界说Handler?

Android Handler is mainly used to update the main thread from background thread or other than main thread.

Google官方文档是这么界说Handler的: 在android中,Handler首要用于从后台线程向主线程同步Message。

总结性的说: android为了更好进行线程通讯,Handler根据双向链表数据结构的 “优先级音讯行列”,提供了一套线程通讯机制。

2.2 Why: 为什么用Handler?

为什么会有Handler存在呢?在Android中,线程分为两种,榜首种是主线程,主线程首要用来创立和更新UI用途。

第二种是后台线程,后台线程首要用于处理耗时的操作,网络恳求、文件读写和音视频播映等后台作业。

后台线程有用地进步运用程序功能,确保UI流程度。

Android硬件规则手机每隔16ms会改写一次,Android为了不丢帧,主线程耗时不能超过16ms。

因而,Android不允许后台线程更新UI。

为了将Message从一个线程传递到另一个线程,完成线程间的通讯,Handler承当了线程切换的责任。

除此之外,Handler还能够发送Message完成守时使命。

2.3 When: 何时运用Handler?

假如需求履行一个使命在指定的时刻间隔或在特定的线程中履行使命时,那么咱们考虑运用Handler机制。

比如: 领导要你完成一个Android音讯轮询库。

2.4 Where: Android结构运用Handler的当地?

在Android结构中,HandlerThread 、IntentService 、EventBus 、RxJava、 DataBinding 和Dagger2都是根据Handler完成的。

2.5 How : 怎样运用Handler?

Handler运用非常简略,创立了一个Handler实例并重写了 handleMessage 办法 ,然后在恰当的机遇调用Handler的 send 或许 post 系列办法就能够了

并发编程   基础篇(中)   三大分析法分析Handler

2.6 How Much: Handler真的完美吗?

Handler有两个缺点,榜首个是不支持跨进程,第二个是形成代码臃肿。

由于Handler是根据内存的,而进程之间的内存是阻隔的,所以Handler不支持跨进程通讯。

一起,假如编写大量的if-else块来处理Message不同的状况,Handler会形成代码变得很臃肿。

三、MECE剖析Handler

MECE全称Mutually Exclusive Collectively Exhaustive,中文意思是“相互独立,完全穷尽”。

对于一个重大意义论题,MECE能够做到不重、不遗失的分类,而且MECE能够根据分类有用把握问题的中心。

接下来,小木箱依照API、音讯机制、高档运用和规划缺点分类剖析Handler, 假如听完小木箱剖析Handler,那么Handler不再是任何人面试的绊脚石。

3.1 Handler常见API

Handler常见API有四个,榜首个是Message,第二个是MessageQueue,第三个是ThreadLocal,终究一个是Looper。

并发编程   基础篇(中)   三大分析法分析Handler

3.1.1 Message

首要,咱们来说说榜首个API,Message,Message要说的东西不多。

依照MECE准则,Message内容首要分为三大类: Message音讯界说、Message数据结构和Message创立办法

Message音讯界说

首要,咱们说说Message音讯界说,Message是音讯的载体,内部参数能够看如下源码:

并发编程   基础篇(中)   三大分析法分析Handler

Message数据结构

然后,咱们说说Message数据结构,Message数据结构是单链表结构,Message会经过next持有了下一个Message引用。

并发编程   基础篇(中)   三大分析法分析Handler

Message创立办法

终究,咱们说说Message创立办法,Message有两种,榜首种创立办法是结构函数创立Message,第二种是经过Message.obtain办法创立Message

并发编程   基础篇(中)   三大分析法分析Handler

可是不建议运用结构函数创立Message,有两个原因,榜首个原因是结构函数创立Message方针不能被重用,导致浪费内存。 第二个原因是结构函数创立Message损坏Handler “优先级音讯行列” ,结构函数创立的Message不会被增加到Handler的 “优先级音讯行列” 中,由于Handler没有当地接收Message。

并发编程   基础篇(中)   三大分析法分析Handler

反之,经过Message.obtain办法创立Message会存储在音讯池recycle中。

3.1.2 MessageQueue

说完Message,咱们说一说第二个API,MessageQueue,依照MECE准则,Message内容首要分为三部分。

榜首部分是MessageQueue界说,第二部分是MessageQueue流程,第三部分是MessageQueue考虑。

MessageQueue界说

首要,咱们来说说MessageQueue的界说,Handler的MessageQueue “优先级音讯行列” 效果是存放Message方针,Handler的MessageQueue数据结构不是行列,Handler的MessageQueue是双向链表数据结构,为什么这么规划呢?由于Handler的MessageQueue能够从头部和尾部一起进行查找操作,查找速度比单链表更快。

考虑: 不同线程的多个 Handler往MessageQueue中增加数据,那么MessageQueue是怎么确保线程安全的?

并发编程   基础篇(中)   三大分析法分析Handler

如上图代码所示,MessageQueue是根据音讯循环完成的,MessageQueue运用两层检查锁和wait/notify机制来确保线程安全。

当一个线程调用MessageQueue.enqueueMessage办法增加音讯时,MessageQueue会先检查锁。

假如锁没有被占用,MessageQueue会获取锁,然后将音讯增加到音讯行列中,终究开释锁。

假如另一个线程正在运用锁,那么MessageQueue会堵塞,直到取得锁,然后才能持续增加音讯。

别的,MessageQueue还运用wait/notify机制来告诉另一个线程,当音讯被增加到音讯行列时,另一个线程将被唤醒。

MessageQueue流程

然后,咱们来说说MessageQueue流程。

MessageQueue流程咱们能够看看如下流程图:

并发编程   基础篇(中)   三大分析法分析Handler

实例化Handler的时分。

首要,Handler会创立一个MessageQueue。

然后,MessageQueue会调用Looper的 loop办法。

接着,发动一个音讯循环来处理Message。

终究,假如没有Message,那么主线程会开释CPU然后回调native的Looper睡觉办法进入休眠状况。

假如有Message,那么会回调native的唤醒办法唤醒CPU。

MessageQueue考虑

终究,咱们说说对MessageQueue考虑。

考虑: MessageQueue.next办法 会由于发现了推迟Message,而进行堵塞。那么为什么后边参加的非推迟Message没有被堵塞呢

MessageQueue.next办法会获取 “优先级音讯行列” (queue的next办法)中的下一条Message,假如发现存在推迟Message,会处理推迟Message,然后再处理非推迟Message。

音讯行列处理Message是有优先级的,因而,参加的非推迟Message不会被堵塞。

并发编程   基础篇(中)   三大分析法分析Handler

3.1.3 ThreadLocal

说完MessageQueue,咱们说一说第三个API,ThreadLocal,依照MECE准则,ThreadLocal内容首要分为三部分。

榜首部分是ThreadLocal效果,第二部分是ThreadLocal原理,第三部分是ThreadLocal和Looper联系。

ThreadLocal效果

ThreadLocal是Java中一个用于线程内部存储数据的东西类,效果是阻隔线程。

咱们看一下如下测试用例:

并发编程   基础篇(中)   三大分析法分析Handler

输出成果:

当时线程: main: true

当时线程: 小木箱: false

当时线程: 小石头: null

ThreadLocal原理

由于线程拜访ThreadLocal时分,当时线程的ThreadLocalMap,会把ThreadLocal变量作为key,传进来的泛型作为value进行存储。

并发编程   基础篇(中)   三大分析法分析Handler

由于线程阻隔导致每个线程能够拜访其线程局部变量,而其他线程无法拜访该线程的局部变量。

也便是说,每个线程都能够独登时改动自己的副本,而不会影响其他线程所对应的副本。

并发编程   基础篇(中)   三大分析法分析Handler

ThreadLocal和Looper联系

由于一个 Looper只能确保只要一个MessageQueue,在线程运用 Looper.prepare办法创立 loop的时分,Looper会从ThreadLocal中获取。

假如ThreadLocal里面有Looper就会抛出反常,那么确保一个线程只要一个 Looper或MessageQueue即可

并发编程   基础篇(中)   三大分析法分析Handler

3.1.4 Looper

说完ThreadLocal,咱们说一说第四个API,Looper,Looper内容首要分为两部分。

榜首部分是Looper界说,第二部分是Looper生命周期。

Looper界说

Looper能够完成线程之间的Message传递。

Handler的Looper接收从其他线程经过dispatchMessage发送Message,并将Message放入一个MessageQueue中,然后在当时线程中按次序处理(handleMessage)Message。

并发编程   基础篇(中)   三大分析法分析Handler

Looper生命周期

依照MECE准则,Looper生命周期分为Looper创立、Looper发动和Looper停止。

Looper创立

Looper创立办法有两种,榜首种是主线程ActivityThread创立Looper,第二种是自己创立Looper。

主线程ActivityThread创立Looper,运用的是prepareMainLooper办法,经过prepareMainLooper办法能够在任何当地获取到主线程的Looper,主线程的Looper不能退出。

并发编程   基础篇(中)   三大分析法分析Handler

自己创立Looper,运用的是prepare办法,终究会调到prepare(boolean quitAllowed)办法,prepare(boolean quitAllowed)办法是private,外部不能直接调用,区别是主线程创立的Looper不能退出,而自己创立的能够退出。

Looper的内部保护了MessageQueue,初始化Looper,即初始了MessageQueue

并发编程   基础篇(中)   三大分析法分析Handler

Looper发动

Looper发动的发动调用的是loop办法,prepareloop办法是配套运用的,两者有必要成对存在,loop的流程如下:

首要,获取当时线程的Looper方针,没有则抛反常。

然后,进入一个死循环: 不断调用MessageQueue的next办法来获取Message。

终究,调用message的方针handler的dispatchMessage办法来处理Message。

Looper发动机制如下:

并发编程   基础篇(中)   三大分析法分析Handler

Looper的loop办法源码如下:

并发编程   基础篇(中)   三大分析法分析Handler

Looper停止

Loop常用的办法有两种,榜首种是quit,第二种是quitSafely。

quit和quitSafely区别在于quit会直接退出Looper,而quitSafely首要设定一个mQuitting标记,然后把MessageQueue中的已有Message处理完毕,终究安全退出。

具体代码如下:

并发编程   基础篇(中)   三大分析法分析Handler

quitquitSafely办法终究都调用了quit(boolean safe)办法,quit(boolean safe)办法先判别是否能退出,然后再履行退出逻辑。

假如mQuitting==true,那么这里会直接return掉。

mQuitting变量只要在quit办法,才会被从头赋值。

因而一旦looper退出,就无法正常运转looper。

当履行退出逻辑,CPU会唤醒MessageQueue,然后MessageQueue的next办法、Looper的loop办法伴随退出,导致线程停止,具体流程图如下:

并发编程   基础篇(中)   三大分析法分析Handler

3.2 Handler音讯机制

Handler音讯机制首要分为三个流程,榜首个流程是Handler发送Message,第二个流程是Looper轮询读取,第三个流程是Handler收回Message

3.2.1 Handler发送Message

首要,咱们说说榜首个流程Handler发送Message,Handler发送Message的办法有两种,榜首种是sendMessage,第二种是post

3.2.1 Handler_sendMessage & post

sendMessage直接发送Message实例方针,而post办法,发送的是一个Runnable,Runnable会被封装进一个Message,发送的实质上也是一个Message

并发编程   基础篇(中)   三大分析法分析Handler

sendMessage 或许 post等系列发送办法会调用到Handler的enqueueMessage办法,而Handler中的enqueueMessage办法终究调用到MessageQueue的enqueueMessage办法。

并发编程   基础篇(中)   三大分析法分析Handler

Handler发送Message全体流程图参阅如下:

并发编程   基础篇(中)   三大分析法分析Handler

3.2.2 MessageQueue_enqueueMessage

说完Handler的sendMessage & post办法,咱们再说说sendMessage & post办法的底层完成enqueueMessage,MessageQueue enqueueMessage等候行列具体流程参阅如下:

并发编程   基础篇(中)   三大分析法分析Handler

MessageQueue的enqueueMessage等候行列源码剖析如下,总共能够分为五个步骤:

并发编程   基础篇(中)   三大分析法分析Handler

榜首步,假如Message中的Handler为空,那么抛不合法参数反常。

第二步,MessageQueue同步锁处理,假如当时线程现已消亡,那么抛不合法参数反常并返回false。

第三步,对Message的when从头赋值,记载正确的时刻。

第四步,将新Message刺进链表,假如messageQueue是空或许正在等候下个推迟Message,那么需求CPU唤醒MessageQueue。

第五步,根据Message的when,找到在链表中刺进位置进行刺进,MessageQueue保护 “优先级音讯行列” ,确保Message是升序的。

3.2.3 MessageQueue_next

Message存放到 “优先级音讯行列” 之后,要对Message进行读取,Looper的Loop办法会从MessageQueue中循环读Message,loop办法调用了queue.next办法

并发编程   基础篇(中)   三大分析法分析Handler

next办法意图是获取MessageQueue中的一个Message,next办法有一个死循环,假如 “优先级音讯行列” 中没有Message,那么next办法会一向堵塞。

假如 “优先级音讯行列” 中有新Message到来,那么next办法会被唤醒,next办法会返回新的Message,并将Message从 “优先级音讯行列” 中移除。

并发编程   基础篇(中)   三大分析法分析Handler

3.2.2 Looper轮询读取

3.2.2.1 从Java层观测Handler

然后,咱们再说说第二个流程Looper轮询读取,Looper的loop办法是一个for死循环,loop办法做了三件事。

榜首件事是调用 MessageQueue的next办法取Message。

第二件事是经过Message的target,也便是Handler去dispatchMessage分发Message。

第三件事是handleMessage收回Message。

其间,MessageQueue的next办法也是一个死循环,首要会调用linux的epoll机制

其间,nextPollTimeoutMillis表明堵塞的时刻,-1表明无限时刻,直到有事件产生停止,0表明不堵塞

假如没有Message或许处理时刻未到,next办法会堵塞,nativePollOnce函数的睡觉时刻是Java层透传的

3.2.2.2 从native层观测Handler

中心完成在Pollinner类中,native有四种状况: 初始化、休眠、唤醒和消亡。

咱们着重说一下休眠和唤醒。

并发编程   基础篇(中)   三大分析法分析Handler
并发编程   基础篇(中)   三大分析法分析Handler

先说说休眠状况,假如监听文件描述符没有产生1和0读写事件,那么当时线程会在epoll wait中进入休眠状况。

然后说说唤醒状况,假如当时线程有新的Message需求处理,那么CPU被唤醒,然后连续之前调用途径,回溯到Java层。

3.2.3 Handler收回Message

3.2.2.1 Looper_loop

Looper和线程是1对1的联系,Looper调用的dispatchMessage办法会运转在不同的线程,所以Message的处理就会被切换到Looper地点线程。

Looper的loop办法调用了msg.target.dispatchMessage(msg) 办法,msg.target 便是发送该Message的 Handler,这样Message终究会回调到Handler的dispatchMessage办法。

并发编程   基础篇(中)   三大分析法分析Handler

3.2.3.2 Looper_dispatchMessage

msg.target.dispatchMessage(msg) 办法,msg.target 便是发送该Message的 Handler,Message终究会回调到Handler的dispatchMessage办法中。

并发编程   基础篇(中)   三大分析法分析Handler

3.2.3.3 Looper_handleCallback

假如Message的callback不为null就经过handleCallBack来处理Message,Message的callback是一个Runnable方针,实践上是Handler的post系列办法传递的Runnable参数。

并发编程   基础篇(中)   三大分析法分析Handler

3.2.3.4 Callback

假如mCallback不为null调用mCallback的handleMessage处理Message,Callback是个接口。

并发编程   基础篇(中)   三大分析法分析Handler

3.2.3.5 new Handler(callback)

经过Callback能够选用如下办法来创立Handler。

并发编程   基础篇(中)   三大分析法分析Handler

3.2.3.6 Handler_handleMessage

终究,调用Handler的handleMessage办法来处理Message

Handler收回Message流程总结图如下:

并发编程   基础篇(中)   三大分析法分析Handler

3.2.4 Handler机制总结

Handler机制首要分为三个流程,榜首个流程是Handler发送Message,第二个流程是Looper轮询读取,第三个流程是Handler收回Message。

并发编程   基础篇(中)   三大分析法分析Handler

首要,咱们说说榜首个流程Handler发送Message,Handler发送Message有两种办法,榜首种办法是Handler的sendMessage,第二种办法是Handler的post发送Message。

Handler的sendMessage能够发送守时和不守时Message两种。

Handler的post实质也是sendMessage形式,只不过传入的Runnable参数包装成Message的Callback。

Message方针传给MessageQueue的enqueueMessage进行优先级入队,enqueueMessage效果是保护一个Message链表,enqueueMessage根据Message的when时刻正序排序,推迟Message是延时时刻+当时时刻进行精准计算。

然后,就第二个流程Looper轮询读取,Looper的loop办法是一个for死循环,loop办法做了三件事。

榜首件事是调用 MessageQueue的next办法取Message。

第二件事是经过Message的target,也便是Handler去dispatchMessage分发Message。

第三件事是handleMessage处理Message。

其间,MessageQueue的next办法也是一个死循环,首要会调用linux的epoll机制

假如没有Message或许处理时刻未到,next办法会堵塞,nativePollOnce函数的睡觉时刻是Java层透传的,中心完成在Pollinner类中,native有两种状况: 休眠和唤醒。

先说说休眠状况,假如监听文件描述符没有产生1和0读写事件,那么当时线程会在epoll wait中进入休眠状况。

然后说说唤醒状况,假如当时线程有新的Message需求处理,那么CPU被唤醒,然后连续之前调用途径,回溯到Java层。

终究,对新Message进行外理。

并发编程   基础篇(中)   三大分析法分析Handler

看完源码,有两点能够深度反思,榜首点是获取Message只能经过Message的obtain获取,不要直接new,由于 Message.obtain会从缓存里面去取。

第二点是能够运用IdleHandler在 “优先级音讯行列” 空闲时提前做一些操作。

实践开发中,点击音讯中心图标,会跳到h5页面。

在url后边加密拼接uid和phoneNumber,加密操作是同步的,所以能够经过IdleHandler提前做这一操作,而且返回 false,表明只做一次。

3.3 Handler高档运用

3.3.1 Handler同步屏障机制

Handler发送的Message会存放到MessageQueue中,MessageQueue保护了一个优先级行列。

优先级行列存储了单链表的Message依照时刻大小进行升序,Looper则按次序,每次从优先级行列中取出一个Message进行分发,处理完一个就处理下一个,有没有办法让指定Message优先消费?

有! 同步屏障机制! 下面又得搬出5W2H剖析法剖析同步屏障机制。

3.3.1.1 What: 同步屏障机制界说

Android的Handler同步屏障机制是一种用来防止多线程间数据竞争的机制,同步屏障机制能够确保多个线程之间的数据同步。

当一个线程的数据在另一个线程中被修改时,Handler会宣布一个信号,以便其他线程能够检查这些数据。

假如数据产生变化,那么Handler会把这些变化发送给其他线程,以确保一切线程都具有最新的数据。

3.3.1.2 Who: 同步屏障机制原理剖析

MessageQueue_next

假如当时msg不为空而且msg.target的Handler方针为空,那么履行同步屏障而且在音讯行列中查询下一个异步音讯,循环遍历查询下一个异步音讯,经过循环体履行相关链表的作业。

并发编程   基础篇(中)   三大分析法分析Handler

在这里咱们提出了榜首个问题。

发送音讯的一系列办法会给msg.target方针赋值,msg.target什么时分赋值为空的呢?

其实target特点为空的Message便是同步屏障,同步屏障能够使得异步Message优先被处理,经过MessageQueue的postSyncBarrier能够增加一个同步屏障。

在异步音讯处理完之后,同步屏障并不会被移除,需求咱们手动移除。

并发编程   基础篇(中)   三大分析法分析Handler

假如不移除同步屏障,那么同步屏障会一向在那里,同步音讯就永远无法被履行。下面咱们跟一下同步屏障源码:

MessageQueue_postSyncBarrier

post和get办法终究都会走MessageQueue的postSyncBarrier的办法,MessageQueue的postSyncBarrier的办法中没有给msg.target方针赋值。

可是postSyncBarrier办法 target特点为空的同步屏障Message,同步屏障Message是特殊的Message,不被消费,作为特殊标识短暂的存储在MessageQueue中。

遇到target为null的Message,说明是同步屏障,循环遍历找出一条异步音讯,然后处理。在同步屏障没移除前,只会处理异步音讯,处理完一切的异步音讯后,就会处于堵塞。假如想康复处理同步音讯,需求调用 removeSyncBarrier() 移除同步屏障

并发编程   基础篇(中)   三大分析法分析Handler

MessageQueue_enqueueMessage

在这里咱们提出了第二个问题。

怎么将把同步屏障音讯变成异步音讯?

有两种办法:榜首种是在Handler的结构办法中,传入async为true,那么这个时分发送的Message就都是异步的的音讯,第二种是给Message经过setAsynchronous 办法标志为异步。

榜首种经过msg.setAsynchronous办法设置为true,能够把一个同步屏障音讯变成异步音讯

并发编程   基础篇(中)   三大分析法分析Handler

Handler(Looper looper, Callback callback, boolean async)

第二种假如满意Handler的mAsynchronous特点为true,那么同步屏障音讯会在Handler的两个结构办法中从头赋值

并发编程   基础篇(中)   三大分析法分析Handler

因而,同步屏障音讯设置为异步音讯。

3.3.1.3 How: 同步屏障机制测试用例

假设当时Message CrazCodingBoy分发给Handler后履行了耗时操作,那么本该到点消费的Message CrazCodingBoy被堵塞了,Message CrazCodingBoy在其他Message sendMessage办法之后,等其他Message消费完再消费当时Message CrazCodingBoy,具体测试用例参阅如下:

并发编程   基础篇(中)   三大分析法分析Handler

输出成果:

count: 10

3.3.1.4 When: 同步屏障机制运用场景

ViewRootImpl快速响应 UI 改写

在进行UI制作的时分,以下是ViewRootImpl中履行UI制作的办法运用到了同步屏障

并发编程   基础篇(中)   三大分析法分析Handler

制作音讯放入优先级音讯行列之前,首要先放入了一个同步屏障,然后在发送异步制作音讯,终究使得界面制作的音讯会比其他音讯优先履行,避免了由于 MessageQueue 中音讯太多导致制作音讯被堵塞导致画面卡顿,当制作完成后,就会将同步屏障移除

3.3.1.5 How Much: 同步屏障机制运用价值

Handler同步屏障机制还能够用于多线程编程中的并发编程,帮助开发者完成多线程之间的同步,进步程序的功能。

3.3.1.6 Why: 同步屏障机制运用原因

为了确保音讯的次序性和正确性,避免音讯的乱序处理和重复处理。

同步屏障机制能够确保在音讯到达Handler之前,一切的音讯都现已处理完毕,而不会出现音讯重复处理的状况。

这样,就能够确保每一条音讯只处理一次,然后确保Handler处理音讯的正确性和次序性。

3.3.2 IdleHandler运用

IdleHandler界说

IdleHandler是一种Android中的回调机制,IdleHandler能够让Android开发运用处于空闲状况时履行特定的操作。

IdleHandler能够用来履行一些定期的使命。

IdleHandler源码剖析

Android IdleHandler运用 Handler.post(Runnable) 办法来将一个Runnable方针放入MessageQueue的next优先级音讯行列中。

当运用程序空闲时,Runnable 方针就会被履行。

当使命完成后,能够运用 Handler.removeCallbacks(Runnable)来从MessageQueue的next优先级音讯行列中移除Runnable方针。

并发编程   基础篇(中)   三大分析法分析Handler

IdleHandler测试用例

并发编程   基础篇(中)   三大分析法分析Handler

输出成果:

queueIdle: 空闲时做一些轻量级别耗时操作

IdleHandler运用场景

最典型的两个事例是: IdleHandler能够获取View宽高和网络连接检测

3.3.3 Looper活学活用

Looper高档运用有两个,榜首个是

榜首个是经过LoopergetMainLooper办法获取主线程Looper,能够判别当时线程是否在主线程

第二个是将 Runnable post到主线程履行

并发编程   基础篇(中)   三大分析法分析Handler

3.3.4 HandlerThread

参阅小木箱生长营的并发编程 根底篇(上) android线程那些事#2.4.1 HandlerThread

3.4 Handler规划缺点

3.4.1 Crash现场还原

并发编程   基础篇(中)   三大分析法分析Handler

并发编程   基础篇(中)   三大分析法分析Handler

指针反常是原因多线程并发,当主线程履行到sendEnptyMessage时,子线程的Handler没有创立。

因而,咱们获取到Handler,再去消费Message就能够了,测试用例咱们让主线程休眠再履行,能够处理Crash问题。

子线程运用Handler,有两点需求注意

榜首点是有必要调用 Looper.prepare()创立当时线程的 Looper,并调用Looper.loop()敞开音讯循环

第二点是有必要在运用完毕后调用Looper的quit办法退出当时线程,否则,假如不退出当时线程,线程的Looper处理完一切的音讯后,会处于堵塞状况,由于线程是重量级的,假如一向堵塞,会影响运用功能。

实践开发过程中,咱们能够搭建一套容灾系统,运用并发编程 根底篇(上) android线程那些事#4.5 UncaughtException兜底计划大局捕获Handler触发的不合法参数反常和空指针反常。规划流程图如下:

并发编程   基础篇(中)   三大分析法分析Handler

3.4.2 后台线程弹Toast

并发编程   基础篇(中)   三大分析法分析Handler

输出成果:

1: “Can’t toast on a thread that has not called Looper.prepare()”

2: 正常运转

剖析源码咱们发现,在后台线程弹吐司时分,有必要初始化后台线程的Looper,否则会报反常

并发编程   基础篇(中)   三大分析法分析Handler

3.4.3 后台线程弹Dialog

同理在后台线程弹对话框时分,有必要初始化后台线程的Looper,否则也会报反常,由于创立Handler,需求先创立Looper并敞开音讯循环,主线程默认创立了并敞开音讯循环,而后台线程并没有。

并发编程   基础篇(中)   三大分析法分析Handler

那么主线程是怎么创立Looper的呢?咱们剖析一下源码

并发编程   基础篇(中)   三大分析法分析Handler

ActivityThread经过ApplicationThread和AMS进行进程间通讯的办法完成ActivityThread的恳求后,会回调ApplicationThread中的Binder办法,然后ApplicationThread会向H发送音讯,H收到音讯后会将ApplicationThread中的逻辑切换到ActivityThread中去履行,即切换到主线程去履行

四、SCQA剖析Handler

SCQA模型是麦肯锡芭芭拉明托在《金字塔原理》中提出的“结构化表达”模板东西,常用于计划、文案、广告、演讲、讲故事、写作和面试等。

SCQA是Situation、Complication、Question和Answer4个英文单词简称。分别是:

  • S(Situation)背景—由⼤家都了解的情景、现实引⼊

  • C(Complication)代表抵触—指的是实践状况和咱们的要求有抵触⼊

  • Q(Question)代表问题—怎么办

  • A(Answer)代表答案—咱们的处理⽅案

咱们在面试的时分一般有场景题、矛盾题和界说题。分别对应着SCQA、CQA和QA三种模型。小木箱总结了33个高频Handler面试题,答案后期将同步到B站,感兴趣能够提前关注一下。

并发编程   基础篇(中)   三大分析法分析Handler

五、结语

三大剖析法剖析Handler首要分为三部分,榜首部分是5W2H剖析Handler,第二部分是MECE剖析Handler,第三部分是Handler规划缺点,第四部分是SCQA剖析Handler。

首要,5W2H剖析Handler针对Handler提出了六个高价值问题。

然后,MECE剖析Handler分为两部分,榜首部分是Handler常见API、第二部分是Handler音讯机制、第三部分是Handler高档运用和Handler规划缺点。

终究,SCQA视频共享了33个Handler高频面试题。

其间,Handler音讯机制首要分为三部分,榜首部分是Handler发送Message、第二部分是Looper轮询读取和第三部分是Handler收回Message。

本文写作意图是用最平滑的言语,帮助我们从原理到完成学习Handler。

企业面试中,Handler算是送分题,作为一名高档Android开发,连Handler都答不会,根本不太可能经过面试,当然怎样使用Handler完善Android容灾系统,文章没有过多的解说,感兴趣能够听一下第12期字节跳动技能沙龙录播课。

下一节,小木箱将带我们学习并发编程 根底篇(下) android线程池那些事。

我是小木箱,假如我们对我的文章感兴趣,那么欢迎关注小木箱的大众号小木箱生长营。小木箱生长营,一个专注移动端共享的互联网生长社区。

参阅资料

/post/693260…

/post/692408…