前语
关于handler,你会想到什么呢?
面试必考?项目常用?系统巨大?
已然它如此重要,不知对面的你了解它多深呢?今天就和咱们一同打破砂锅问究竟,看看Handler
这口砂锅的底究竟在哪里。
二十七问,从问题的视点再读Handler。数组c言语
纲要
1、面试问题Hanappointmentdler被规划出来的原因?有什么用?
一种东西被规划出来必定就有它存在的含义,而Handler
的含义便是切换线程。
作为Android
音讯机制的首要成员,它处理着悉数与界面有关的音讯作业,常见的运用场景有:
- 跨进程之后的界面音讯处理。
比方Activity的建议,便是AMS在进行进程架构图怎样做word间通讯的时分,经过Binder线程 将音讯架构规划发送给ApplicationThrappstoreead
的音讯处理者Handler
,然后再将音讯分发给主线程中去实施。安全教育渠道
- 网络交互后切换到主线程进行UI更新
当子面试必问10大问题答复线程网络操作安全之后,需求切换到主线程进行UI更新。
总之一句话数组词,Hanlder
的存在便是为了处理在子线程中无法拜访UI的问题。
2、为什么建议子线程安全出产法不拜访(更新)UI?
由于Android
中的UI控件不是安全教育线程安架构师需求把握哪些常识全的,假定多线程拜访UI控件那还不乱套了。
那为什么不加锁呢?
-
会下降UI拜访的功率
。自身UI控件便是离用户比较近的一个组件,加锁之后自然会产生堵塞,那么UI拜访的功率会下降,究竟反应到用户端便是这个手机有点卡。 -
太凌乱了
。自身UI拜访时一个比较简略的操作逻辑,直接创立UI,批改UI即可。假定加锁之后就让这个UI拜访的逻appearance辑变得很凌乱,没必要。
所以,Android规划出了 单线程模型
来处理UI操作,再搭配上Handler,是面试技巧和注意事项一个比较适合的处理计划。
3、子线程拜访UI的 溃散原因 和 处理办法?
溃散产生在ViewRootImpl类的checkThread
办法中:
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the数组排序 origin架构图模板al thread that created a view hi数组排序erar数组初始化chy can touc架构师证书怎样考h its views.");
}
}
其实便是application判别了当时线程 是否是 ViewRootImpl
创立时分的线程,假定不是,就会溃散。
而数组初始化ViewRootImpl创立的时机便是界面被制作的时分,也便是onResume之后,所以假定在子线程appearance进行UI更新,就会发现当时线程(子线程)和View创立的线程(主线程)不是同一个线程,产生溃散。
处理办法有三种:
- 在新建视图的线程进行这个视图的UI更新,主线程创立View,主线程更新View。
- 在
ViewRootImpl
创立之前进行子线程的UI更新,比方onCreate办法中进行子线程更新UI。 - 子线程切换到主线程进行UI更新,比方
Handler、view.post
办法。
4、MessageQueue是干嘛呢?用的什么APP数据结数组词构来存储数据?数组词
看名字应该是个部队结构,部队的特征appearance是什么?先进先出
,一般在队尾添加数据,在队首进行取数据或许删去数据。
那Hanlder
中的音讯如同也满足这样的特征,先发的音讯必定就会先被处理。可是,Handler面试问题大全及答案大全
中还有比较特别的状况,比方延时音讯。
延时音讯的存在就让这个部队有些特别性了,并不能完全确保先进先出,而是需求依据时刻来判别,所以Android
中架构是什么意思选用了链表的办法来完毕这个部队,也便当了数据的刺进。
来一同看看音讯的发送进程,无论是哪种办法发送音讯,都会走到sendMessageDelayed
办法
public架构师 final boolappleean s架构师需求把握哪些常识endMessageDe数组去重的5种办法layed(@NonNull Mappstoreessage msg, long delayMillis) {
if (delayMillis &l数组初始化t; 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.upapproachtimeMillis() + delayMillis);
}
public bo数组和链表的差异olean sendMessageAtTime(@NonNull Mesappstoresage msg, long uptimeMillis) {
MessageQueue queue = mQueue;
return enqueueMessage(架构师需求把握哪些常识queue, msg, uptimeMillis);
}
sendMessageDelayed
办法首要计算了音讯需求被处理的时刻,假定delayMillis
为0,那么音讯的处理时刻便是其安全出产法时时刻。
然后便是要害办法enqueueMessage
。
boolean enque面试技巧和注意事项ueMessage(Message msg, long when) {
synchronized (this面试问题大全及答案大全) {
msg.markInUse();
msg.when = when;
Messa面试毛遂自荐ge p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
m数组去重sg.next = p;
mMessages架构师和程序员的差异 = msg;
needWake = mBlocked;
} else {
needWake = mBlapplicationocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || whe架构是什么意思n < p.when) {
break;
}
if (needWake && p.i数组去重的5种办法sAsynchronous()) {
needWake = fals数组和链表的差异e;
}
}
msg.next = p;
prev.n架构师ext = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
不懂得当地先不看,只看咱们想看的:
- 首要设置了
Message面试问题
的when字段,也便是代表了这个音讯的处理时刻 - 然后判别当时部队是不是为空,是不是即时消apple息,是不是实施时刻when大于表头的音讯时刻,满足任意一个,就把当时音讯msg刺进到表头。
- 否则,就需求遍历这个部队,也便是
链表
,找出when小于某个节点的when,找到后刺进。
好了,其他内容暂且不看,总之,刺进音讯便是经过音讯的实施时刻,也便是when
字段,来找appear到适合的方位架构师需求把握哪些常识刺进链表。
详细办法便是经过死循环,运用快慢指针p和prev,每次向后移动一格,直到找到某个节安全期点p的when大架构师需求把握哪些常识于咱们要刺进音讯的when字段,则刺进到p和pre安全出产法v数组公式之间。
或许遍历到链表完毕,刺进到链表完毕。
所以,MessageQueue
便是一个用于存储音讯、用链表完毕的特别部队结构。
5、推APP延消面试息是怎样完毕的?
总结上述内容appreciate,推迟音讯的完毕首要跟音讯的一致存储办法有关,也便是上文说过的enqueueMessage
办法。
无论是即时音讯仍是推迟音讯,都是计算出详细的时刻,然后作为音讯的when字段进程面试必问10大问题答复赋值。
然后在M架构师薪酬一月多少essageQueue中找到适合的方位(组安全出产法织when小到大摆放),并将音讯刺进到MessageQue数组初始化ue
中。
这样,MessageQueue
便是一个按照音讯架构图模板时刻摆放的一个链表结构。
6、MessageQueue的音讯怎样被取出来的?
方才说过了音讯的存储,接下来看看音讯的取出,也便是queue.next
办法。
Message next() {面试毛遂自荐一分钟
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands()架构图怎样做word;
}
nativePollOnce(架构师薪酬一月多少ptr, nextPollTiappearmeoutMilli架构师薪酬一月多少s);
synchronized (thiappointments) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMill数组排序is();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous安全教育渠道登录进口());
}
if (msg != null) {
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(ms安全出产法g.when - now, IAPPnteger.MAX_VALUE);
} else {
// Got a message.
mBlocked = f架构图怎样做alse;
if (prevMsg != null) {
prevMs安全教育渠道登录进口g.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} elseappearance {
// No more messages.
nextPollTimeoutMillis = -1;
}
}
}
}
乖僻,为什么取音讯也是用的死循环呢?
其实死循环便是为了确保必定要回来一条音讯,假定没有可用音讯,那么就堵塞在这儿,一向到有新音讯的到来。
其间,nativePollOnce
办法便是堵塞办法,nextPollTimeoutMillis
参数便是数组堵塞的时刻。
那什么时分会堵塞呢?两种状况:
- 1、有音讯,可是当时时刻小于音讯实施时刻,也便是代码中的这一句:
if (now < msg.when) {
nextPollTim面试必问10大问题答复eoutMillis = (int) Matappreciateh.miapp装置下载n(msg.when - now, Integer.MAX_VALUE);
}
这时分堵塞时刻便是音讯时刻减去当时时刻,然后进入下一次循环,堵塞。
- 2、没有音讯的时分,也便是上述代码的究竟一句:
if (msg != null) {}
else {
// No more messages.
ne面试问题大全及答案大全xtPollTimeoutMillis = -1;
}
-1
就代表一向堵塞。
7、MessageQueue没有音讯时分会怎样?堵塞之后怎样唤醒呢?说说pipe/epoll机制?
接安全期是哪几天着上文的逻辑,当音讯不可用或许没有音讯的时分就会堵塞在next办法,而面试技巧和注意事项堵塞的安全出产法办法是经过piAPPpe/epoll机制
epoll机架构图怎样做制
是一种IO多路复用的机制面试必问10大问题答复,详细逻辑便是一个进程能够监督多个描述符appointment,当某个描述符安排稳妥(一般是读安排稳妥或许写安排稳妥),能够告知程序进行相应的读写操作,这个读写操架构图怎样做word作是堵塞的。在Android中,会创立一个Linux管道(Pipe)
来处理堵塞和唤醒。
- 当音讯部队为空,管道的读端等候管道中有新内容可读,就会经过
epollapplication
机制进入堵塞状态。 - 当有音讯要处理,就会经过管道的写端写入内容,唤醒主线程。架构师薪酬一月多少
那什么时分会怎样approve唤醒音讯部队线程呢?
还记得方才刺进音讯的en架构师queue安全出产法Message
办法中有个needWake
字段吗,很明显,这个便是标明是否唤醒的字段。
其间还有个字段是mBlocked
,看数组的界说字面意思是堵塞的意思,去代码里边数组c言语找找:
Message next() {
for (;;) {
synchronized (this) {
if (msg != null) {
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} elseapproach {
// Got a message.
mBlocked = false;
return msg;
}
}
if (pendingIdleHandlerCount面试问题 <=架构师证书怎样考 0) {
// No idle handlers t数组和链表的差异o run. Loop and wait some more.
mBlocked = true;
continue;
}
}
}
}
在获取音讯的办法next
中,有两个当地对mBloc安全ked
赋值:
- 当获取到面试技巧音讯的时分,
mBlocked
赋值为false
,标明不堵塞。 - 当没数组有音讯要处理,也没有
idleHandler
要处理的时分,mBlocked
赋值为true
,标明安全出产法堵塞。
好了,的确这安全出产法个字段架构图怎样做就标明是否堵塞的意思,再去看看enqueueMessage
办法中,唤醒机制:
boolean enqueueMessage(Message msg数组初始化, long when) {
synchr安全教育onized (this) {
bool安全期ean needWake;
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked架构师需求把握哪些常识;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message pr数组公式ev;
for (;;) {appstore
prev = p;
p = p.next;
if (p == null || when < p.when) {
b数组的界说reak;
}
if (needWake && p.isAsynchronous(面试问题大全及答案大全)) {
needWappointmentake = false;
}
}
msg.next = p;
prev.next = msg;
}
if (needWake) {
native面试毛遂自荐Wake(mPtr);
}
}
return true;安全
}
- 当链表为空或许时刻小于表头架构图怎样做音讯时刻,那么就刺进表头,而且设置是否唤醒为
mBlocked
。
再结合上述的appointment比方,也便是当有新音讯要刺进表头了,这时分假定之前是堵塞状态(mBlocked=true),那么就要唤醒线程了。
- 否则,就需求取链表中找到某个节点并刺进音讯,在这之前需求赋值
needWake = mBlocked &&数组指针 p.target ==安全教育渠道登录进口 null && msg.isAsynchronous()
也便是在刺进APP音讯面试毛遂自荐一分钟之前,需求判别是否堵塞,而且表头是不是屏障音讯,而且当时音讯是不是异步消面试毛遂自荐简略大方息。
也便是假定安全期现在是同步屏障方式下,那么要刺进的音讯又数组刚好是异步音讯,那就不必管刺进音讯问题了,直接唤醒线程,由于异步音讯需求先实施。
- 究竟一点,安全期计算器是在循环里,假定发现之前架构师和程序员的差异就存在异步音讯,那就仍是设置是否唤醒为面试技巧
false
。
意思便是,假定之前有异步音讯了,那面试毛遂自荐简略大方必定之前就唤醒过了,这时分就不需求再次唤醒了。
究竟依据needWake
的值,选择是否调用nativeWake
办法唤醒next()
办法。
8、同步屏障和异步音讯是怎样完毕的?
其实在Handler
机制中安全,有三种音讯类型:
-
同步音讯
。也架构图怎样做word便是一般的音讯。 -
异步消架构是什么意思息
。经过setAsynchrono架构规划us(true)设置的音讯。 -
同步屏障音讯
。经过postSyncBarrier办法添加的音讯,特征是targe面试技巧t为空,也便是没有对应的handler。
这面试技巧三者之间的联络怎样呢?
- 正常状况下,同步音讯和异步音讯都是面试技巧和注意事项正常被处理,也就安全手抄报是依据时刻数组的界说when来取音讯,处理音讯。
- 当遇到同步安全屏障音讯的时分,就初步从音讯部队里边去找异步音讯,找approach到了再根安全据时刻选择堵塞仍是回架构师需求把握哪些常识来音讯。
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg面试必问10大问题答复.next;
} whapp装置下载ile (msg != null && !msg.isAsynch架构是什么意思ronous());
}
也就架构师需求把握哪些常识是说同步屏障音讯不会被回来,他仅仅一个标志,一个工具,遇到它就代表要去先行处理异步音讯了。
所以同步屏障和APP异步音讯的存在的含义就在于有些音讯需求“加急处理”
。
9、同步屏障和appreciate异步音讯有详细的运用场景吗?
运用场景就许多了,比方制作办法scheduleTraversals
。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 同步屏障,堵塞悉数的同步音讯
mTraversalBarrier = mHandler.getLooper().getQu数组指针eue().postSyncBarrier(面试毛遂自荐3分钟通用);
// 经过 Ch架构图怎样做oreographer 发送制作使命
mChoreographer.postC安全手抄报allback(
Choreographer.CALLB架构图怎样做ACK_TRAVERSAL, mTr安全aversalRunnable, null);
}
}
Message msg = mHandler.o架构师btainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1数组词 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueT面试毛遂自荐简略大方ime);
在该办法中参加了同步屏安全期计算器障,后续参加一个异步音讯MSG_DO_SCHEDULE_CALLBACK
,究竟会实施到安全出产法FrameDisplayEventReceiver
,用于恳求VSYNC信号。
更多Choreographer
相关内容能够看看这篇文章——w面试ww.jianshu.com/p/86d00bbda…
10、Messag架构师e音讯被分发之后会怎样处理?音讯怎样复用的?
再看看loop办法,在音讯被分发之后,也便是实施了dispatchMessage
办法面试技巧之后,还偷偷做了一个操作——rec架构师薪酬一月多少ycleUnchecked
。
public static void loop() {
fapproveor (;安全;) {
Mapproachessage msg = qu面试问题大全及答案大全eue.next(); // might block
try {
msg.target.dispatchMe安全ssage(msg);
}
msg.recycleUnchecked();
}
}
//Messa架构师薪酬一月多少ge.java
private static Message sPool;
private static final int MAX_POOL_SIZE = 50;
void recycleUnchecked() {
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPoolappstore =安全 this;
sPoolSize++;
}
}
}
在recycleUnchecked
办法中,开释了悉数资源,然后将当时的空音讯刺进到sP面试毛遂自荐3分钟通用ool安全表头。
这儿的sPool
便是一个音讯政策池,它也是一数组的界说个链表结构的音讯,最大长度为50。
那么Message又是怎样复用的呢?在Message的实例化办法obtain
中:
publ面试毛遂自荐简略大方ic sta面试毛遂自荐一分钟tic Message obtain() {
synchronized (架构规划sPoolSync) {
if (sPool != null) {
Message m = sPool;安全期是哪几天
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Messaappearancege();
}
直接复用音讯架构是什么意思池sPool
中的第一条音讯,然后sPool指向下一个节点,音讯池数量减一。
11、Looper是干嘛呢?怎样获取当时线程的Looper?为什么不直接用Map存储线程和政策呢?
在Handler发送音讯之后,音讯就被存储到MessageQueuapplicatione
中,而Loo面试技巧per
便是一个处理音讯部队的角色。
Looper会从MessageQueue
中不断的查找音讯,也就安全是loop办法,并将音讯交回给架构师薪酬一月多少H架构师和程序员的差异andler进行处理。安全手抄报
而Looper的获取便是经过ThreadLocal
机制:
static final Thr架构规划eadLocal<Looper> sThreadLocal = new Thread数组去重Local<安全期计算器;Looper>架构师证书怎样考;();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreappleadLocal.set(new Loop面试问题er(quitAll安全owed));
}
publi数组c static @Nullable Looper myLooper() {
return sT架构规划hreadLoc面试技巧和注意事项al.get();
}
经过prepare
办法创立Looper而且参加到sThreaappearancedLocal中,经过myLooper
办法从sThreadLocal安全教育渠道登录进口中获取Looper。
12、ThreadLocal作业机制?这种机制规划的长处?
下面就详细说说Thr架构师需求把握哪些常识eadLoc面试毛遂自荐3分钟通用al
作业机制。
//ThreadLocal.java
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
i面试必问10大问题答复f (e != null) {
@SuppressW安全手抄报arnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
Thread t = Threa面试毛遂自荐3分钟通用d.currentThread();
ThreadLocalMap map = getMa数组公式p(t);
if (map != null)
map.set(this, value);安全出产法
else
createMap(t, value);
}
从Thr数组c言语eadLocal
类中的get和set办法能够大致看出来,有一个ThreadLocalMap
变approach量,这个变量存储着键值对办法的数据。
-
key
为this,也便是当时ThreadLocal变量。 -
value
为T,也便是要存储的值。
然后持续看看ThreadLocalMap
哪来的,也便是getMap办法:
//ThreadLocal.java
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//Thread.java
Thr安全教育eadLocal.ThreadLocalMap threadLo面试毛遂自荐简略大方cals = null;
本来这个ThreadLocalMap
变量是存储架构是什么意思在线程类架构师证书怎样考Thread中的。
所以ThreadLocal
的根柢机制就搞清楚了:
在每个线程中都有一个threadLocals变量,这个变量存储着ThreadappstoreLocal和对应的需求保存的政策。
这样带来的长处便是,在不同的线程,拜访同一个Threa安全出产法dLocal政策,可是能获取到数组去重的5种办法的值却不相同。
挺共同的是不是,其实便是其内部获取到的Map不同,Map和Thread绑定,所以尽管拜访的是同一个ThreadLocal
政策,可是拜访的Map却不是同一个,所以获得值也不相同。
这样做有什么长处呢?为什么不直接用Map存储线程和政策呢?
打个比方:
-
Thr数组指针eadLocal
便是教师。 -
Thread
便是同学。 -
Looper
(需求的值)就架构师和程序员的差异是铅笔。
现在教师买了一批铅笔,然后面试想把这些铅笔数组初始化发给同学们,怎样发呢?两种办法:
- 1、教师把每个铅笔上写好appstore每个同学的名字,放到一个大盒子里边appearance去(map),用的时分就让同学们自己来找。
这种做法便是Map里数组的界说面存储的是同学和铅笔
,然后用的时分经过同学来从这个Map里找铅笔。
这种做法就有点像运用一个Map,存储悉数的线程和政策,欠好的当地就在于会很紊乱,每个线程之间有了联络,也简略构成内存走漏。
- 2、教师把每个铅笔直接发给每个同学,放到同学的口袋里(map),用的时分每个同学从口袋里边拿出铅笔就能够了。
这种做法便是Map里边存储的是面试教师和铅笔
,然后用的时分教师说一声,同学只需求从口袋里拿出来就行了。
很approach明显这种做法更科学,这也便是ThreadLocal
的做法,由于铅笔自身便是同学安全期自己在用,所以一初步就把铅笔交给同学自己保管是最好的,每个同学之间进行阻隔。
13、还有哪些当地运用到了ThreadLocal机制?
比方:Choreographer。
public安全教育渠道登录 final class Choreographer {
// Thread local storage架构师薪酬一月多少 for the choreographer.
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographeappreciater>() {
@Overr数组去重ide
protected Choreographer initialValue() {
Looper looper = Looapp装置下载per.myLooper();
if (looper == null) {
throw new IllegalStateException("The curr数组ent thread must have a looper!");
}
Choreographer choreographer = new Choreographer(looper, VSYN架构图怎样做C_SOURCE_APP);
if (looper == LooAPPper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreogr面试技巧apher;
}
};
private static volatile Ch安全oreographer mMainIns数组初始化tance;
Choreographer
首要是主线程用的,用于协作 VSYNC
连续信号。
所以这儿运用ThreadLocal
更多的含义在于完毕线程单例的功用。
14、能够屡次创立Looper吗?
Looper的创立是经过Looapp装置下载per.prepare
办法完毕的,而在prepare办法中就判别了安全期是哪几天,当时线程是否存在Looper政策,假定有,就会直接抛出失常:
private static void pre面试毛遂自荐3分钟通用pare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
t数组的界说hrow new RuntimeException("Only one Looper may be cre安全期是哪几天ated per thread");
}
sThreadLocal.set(new Looper(qui面试问题大全及答案大全tAllowed));
}
private Looper(boolean quitAllowed) {
mQueue =架构师需求把握哪些常识 new面试毛遂自荐 MessageQueu数组公式e(qu面试常见问题及答复技巧itAllowed);
mThread = Thread.currentThread();
}
所以同一个线程,只能创立一个Looper
,屡次approach创立会报错。
15、Looper中的qui面试必问10大问题答复tAllo架构图怎样做wed字段是啥?有什么用?
按照字面意思便是是否允许退出,咱们看看他application都在哪数组的界说些当地用到了:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateE安全教育渠道xception("Main thread not allowed to quit.");
}
s数组的界说ynchronized (this) {
if (mQuitting) {
return;
}
mQu数组c言语itting = true;
if (safe) {
removeAllFutu安全教育reMessagesLocked();
} else {
removeAllMessagesLocked();
}
}
}
哦,便是这个q面试问题大全及答案大全uit
办法用到了,假定这个字段架构师薪酬一月多少为false
,代表不允许退出,就会报错。
可是这个quit
办法又是干嘛的呢?历来没用过呢。
还有这个safe
又是啥呢?
其实看名字就差不多能了解了,quit办法便是退出音讯部队,连续安全教育渠道登录音讯循环。
- 首要设置面试问题了
mQuitting数组c言语
字段安全为true。 - 然后判别是否安全退出,假定安全退出,就实施
removeAllFutu安全reMessagesLocked
办法,它内部的逻辑是清空悉数的推迟音讯,之前架构没处理的非推迟音讯仍是需求取处理,然后设置非推迟音讯的下架构师和程序员的差异一个节点为空(p.next=null)。 - 假定不是安全退出,就实施
removeAllMessagesLocked
办法,直接清空悉数的消面试技巧和注意事项息,然后设置音讯部队指向空(mMessages = null)
然后看看当调面试毛遂自荐一分钟用quit办法之后,音讯的发送和处理:
//音讯发送
boolean enq安全教育渠道登录ueueMess安全教育age(Message msg, long when) {
synchr架构师需求把握哪些常识onized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " send架构图怎样做wording message to a Handler on a de面试问题大全及答案大全ad thread");
Log.w(TAG, e.g面试毛遂自荐简略大方etMessage(), e);
msg.recycle();
ret数组去重urn false;
}
}
当调用了quit办法之后,mQuitting
为true,音讯就发不出去了,会报错。
再看看音讯的处理,loop和next办法:
Message安全手抄报 next() {
for (;;) {
synchronized (this) {
if (mQuitting) {
dispoapplese();
return null;
}
}
}
}
public static void loop() {
for (;;) {
Message msg = queue.next()面试毛遂自荐简略大方;
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
}面试毛遂自荐简略大方
}
很明显,当mQuitting
为true安全教育的时分,next办法回来安全期null,那么l数组排序oop办法中就会退出死循环。
那么这个quit
办法一般是什么时分数组和链表的差异运用呢?
- 主线程中,一般状况下必定不能退出,由于退出后主线程就面试问题连续了。所以是当APP需面试必问10大问题答复求退出的时分,就会调用quit办法,涉及到的音讯是EXIT_APP架构师薪酬一月多少LICAT数组的界说ION,咱们能够查找下。
- 子线程中,假定音讯都处理完了,就需求调用quit办法连续音讯循环。
16、Looper.loop办法是死循环,为什么不会卡死(ANR)?
关于这个问题,安全教育渠道登录强烈建议看看面试技巧和注意事项Gityuan的答复:www.zhihu.c架构规划om/question/34…
我大致总结下:
- 1、主线程自身便是需求一只作业的,由于要处理各个View,界面改变。所以需求这个死循环来确保主线程一向实施下去,不会被退出。
- 2、实在会卡死的操面试技巧作是在某个音讯处理的时分操作时安全间过长,导致掉帧、ANR,而不是面试loop办法自身。
- 3、在主线程以外,会有其他的线程来处理承受其他数组公式进程的作业,比方
Binder线程(ApplicationThr架构师ead)
,会承受AMS发送来的作业 - 4、在收到跨进程音讯后,会安全期计算器交给主线程的
Hanlder
再进行音讯分发。所以Activ架构ity的生命周期都是依托主线程的Looper.架构师证书怎样考loop
,当收到不同Message时则选用相应措施,比方收到msg=H.LAUNCH_ACTI面试技巧和注意事项VITY
,则调用ActivityThread.handleLaunchActivity()
办法,究竟实施到onCreate办法。 - 5、当没有音讯的时分,会堵塞在loop的
queue.next()
中的nativeP面试必问10大问题答复oapproachllOnce()
办法里,此刻主线程会开释CPU资源进入休眠状appstore态,直到下个音讯抵达或许有事务产生。所以死循环也不会特别消耗CPapp装置下载U资安全教育源。
17、Message是怎样找到它所属的Handler然后进行分发的?
在loop办法中,找到要处理的Messageapple
,然后调用了这么一句代码处理音讯:
msg.targeappstoret.dispatchMessage(msg);
所以是将数组的界说音讯交给了msg.target
来处理,那么这个target是啥呢?
找找它的来头:
//Handler
private boolean enqueueMessage(MessageQueue数组公式 queue,Me面试毛遂自荐一分钟ssage msg,long uptimeMi架构是什么意思llis) {
msg.target = this;
return queue.enqueueMes架构规划sage(msg, uptimeMillis);
}
在运用数组去重的5种办法Hanlder发送音讯的时分,会设置msg.target = this
,所以target便是开始把音讯加到音讯部队的那个Handler。
18、Handler 的 post(Runnable) 与 sendMessage 有什么差异
Hanlder中首要的发送音讯能够分为两种:
- post(Runnable)
- sendMessage
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message g数组和链表的差异etPostMessage(Runnable r) {
Message m = Message.obtain();安全教育渠道
m.callback = r;
return m;
}
经过post的源码可知,其实post和send面试问题Message
的差异就在于:
post办法给Message设置了一个callb安全教育渠道ack
。
那么这个callback有什么用呢?咱们再转到音讯处理的办法dispatchMessage
中看看:
public void dispatchMess面试毛遂自荐一分钟age(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
privappreciateate static void handleCallback(Message message) {
message.callback.run();
}
这段代码能够分为三部分看:
- 1、假定
msg.callback
不为空,也就数组去重的5种办法是经过post办法发送音讯的时分,会把音讯交给这个msg.callback进行处理,然后就没有后续了。 - 2、假定
msg.callback
为空,也便是经过sendMessage发送音讯的时分,会判别Handler当时的mCallback是否为空,假定不为空就交给Handler.Callback.handleM架构essage处理。 - 3、假定
mCallback.hanappeardleMessage
回来true,则无后续了。 - 4、假定
mCallback.handleMessage
回来false,则调用handler类重写的handleMessage办法。
所以post(Runnable) 与 se数组排序ndMessage的差异就在于后续音讯的处理办法,是交给msg.架构规划callback
仍是 Handler.Callback
或许Handler.handleMessage
。
19、Handler.Callback.handleMess数组age 和 Handler.handleMess架构师age 有什么不相同?为什么这么规划?
接着上面的代码说,这两个处理数组c言语办法的差异在于Handler.Callback.handleMess架构规划age
办法是否回来true:
- 假定为
true
,则不再实施Hand面试毛遂自荐简略大方ler.handleMessage - 假定为
false
,则两个办法都要实施。面试毛遂自荐简略大方
那么什么时分有Callback
,什么时分没有呢?这涉架构师和程序员的差异及面试问题大全及答案大全到两种Hanlder的 创立办法:
val handler架构师1=面试毛遂自荐3分钟通用 object : Handler()数组排序{
override fun handleMessage(msg: Message) {
super.ha面试常见问题及答复技巧ndleMessage(msg)
}
}
val handler2 = Handler(object : Handler.Call安全back {
override fun handleMes安全期是哪几天sage(msg: Message): Boolea数组初始化n {
return true
}
})
常用的办法便是第安全教育1种,派生一个Handler的子类并重写handleMessage办法。
而第2种便是系统给数组c言语咱们供应了一种不需求派生子类的运用办法,只需求传入一个Callback即可。
20、Handler、Looper、MessageQueue、线程是一一对应联络吗?
- 一个线程只会有一个
Looper
方数组c言语针,所以线程和Looper是一一对应的。 -
MessageQueue
政策是在new Looper的时分创立的,所以Loope安全r和MessageQueue是一一对应的。架构规划 -
Handler
的效果仅仅将音讯加到MessageQ架构图怎样做ueue中,并后续取出音讯后,依据音讯的APPtarget字段分发给开始的那数组初始化个handler,所以Handler关于Looper是能够多对一的,也便是多个Hanlder政策都能够用同一个线程数组初始化、同一个Looper、同一个MessageQueue。
总结:Loo架构师证书怎样考per、MessageQueue、线程是一一对应联络,而他们与Handler是能够一对多的。
21、ActivityThread中做了哪些关于Handler的作业?(为什么主线程不需求独自创安全教育渠道登录进口建Looper)
首要做了两件事:
- 1、面试毛遂自荐3分钟通用在main办法中,创立了面试技巧和注意事项主线程的
L安全教育渠道登录进口ooper
和MessageQueue
,而且调用loop办法敞开了主线程的音讯循环。
public static void mappstoreain(String[] args) {
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {面试毛遂自荐3分钟通用
sMainTh面试技巧readHandler = thread数组.getHandler();
}
Looper.loo面试必问10大问题答复p();
t架构师hr安全教育渠道登录ow new RuntimeException("Ma数组去重in thread loop u安全教育渠道登录nexpectedly exited");
}
- 2、创立了一个Handler来进行四大组件的面试问题大全及答案大全建议连续等作业处理
final H mH = new H();
class H extends Handler {
publ面试技巧ic static fin安全教育渠道登录al int BIND_APPLICATION = 110;
public static f面试必问10大问题答复inal int面试必问10大问题答复 EXIT_APPLICA架构师和程序员的差异TION = 111;
public数组和链表的差异 static final int RECEIVER = 113;
pu面试毛遂自荐3分钟通用blic static final int CREATE_SERVICE = 114;
public static final int STOP_SERVICE = 116;
public static final架构师证书怎样考 int BIND_S架构师和程序员的差异ERVICE = 121;
22、IdleHandler是啥?有什么运用场景?
之前说过,当MessageQueue
没有音讯的时分,就会堵塞在next办法中,其实在堵塞之前,MessageQueue
还会做一件事,便是检查是否存在IdleHandler
,假定有,就会去实施它的queueIdle
办法。
private IdleHandler[] mPendingIdleHandlers;
Message next() {
int pendingIdleHandlerCount = -1;
for (;;) {
synchronized (this) {
//当消安全出产法息实施完毕,就设置pendingIdleHandlerCount
if (pendingIdleHandlerCount < 0
&a安全mp;& (mMessa数组去重的5种办法ges == null || now < mMessages.wh数组初始化en)) {
pen面试必问10大问题答复dingIdleHandlerapp装置下载Count = mIdleHandlers.size();
}
//初始化mPendingId安全出产法leHandlers
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
//mIdleHandlers转为数组
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleH数组去重andlers);
}
// 遍历数组,处理每个IdleHandler
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
bo架构图怎样做olean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
//假定queueIdle办法回来false,则处数组的界说理完就删去这个IdleHandler
if (!keep) {
synchronized (this) {
mIdleHandlers.reappointmentmove(idler);
}
}
}
// Res数组排序et the idle hanappointmentdler count to 0 so we do not run tappreciatehem again.
pending安全教育渠道登录IdleHandlerCount = 0;
}
}
当没有音讯处理的时分,就会去处理这个mIdleHandlers
调集里边的每个IdleHan安全dler
政策,并调用其queueIdle
办法。
究竟依据queueIdle
回来值判别是否用完删去当时的IdleHandler
。
然后看看IdleHandler
是怎样加进去的:
Looper.mapp装置下载yQueue().addIdleHandler(new IdleHandle架构师需求把握哪些常识r() {
@Override
public boolean queueIdle() {
//做作业
retur架构师证书怎样考n false;
}
});
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handapproveler == null) {
throw new NullPointerExcep安全期tion("Can't add a null IdleHandler");
}
s架构师薪酬一月多少ynchronized (this) {
mIdleHanappreciatedlers.架构add(handler);
}
}
ok,综上所述,IdleHandler
便是当音讯部队安全出产法里边没有当时要处理的音讯了,架构图模板需求堵塞之架构师证书怎样考前,能够做一些闲暇使命安全的处理。
常见的运用场景有:建议优化
。
咱们一般会把一些作业(比方界面view的制作、赋值)放架构师证书怎样考到onCreate
办法或许onRe架构师需求把握哪些常识sume
办法中。
可是这两个办法其实都是在界面制作之前调用的,也便是说必定程度上这两appstore个办法的耗数组去重的5种办法时会影响到建议时刻。
所以咱们能够把一些操作放到IdleHandler
中,也便是界面制作完毕之后才去调用,这样就能减少建议时刻了。
可是,这儿需求注意下或许会有坑。
假定运用不妥,IdappearleHandler
会一向不实施,比方在View的o面试必问10大问题答复nDraw办法
里边无限制的直接appearance或许直接调用Vie安全手抄报w的invalidate办法
。
其原因就在于onDraw办法中实施invalidate
,会添加一个同步屏障音讯,在等到异步音讯之前,会堵塞在next办法approve,而等到Fram面试毛遂自荐一分钟eDisplayEventReceiver
异步使命之后又会实施onDraw办法,然后无限循环。
详细能够看看这篇安全教育文章:mp.weixin.qq.com/s/dh_71i8J5…
23、HandlerThread是啥?有什么运用场景?
直接看源码:
public class HandlerThread extends Thread {
@Override
public void run() {
Looper.pre面试毛遂自荐pare();
synchronized (this) {
mLooper架构是什么意思 = Lo架构规划oper.myLoop面试问题大全及答案大全er();
notifyAll();数组去重
}
Process.setTh安全期readPriority(mPriority);
onLooperPrepared();
Looper.loop();
}
哦,本来如此。Hand安全lerThread
便是一个封装了Looper的Thread类。
便是为了让咱们在安全期计算器子线程里边更便当的运用Handler。
这儿的加锁便是为了确保线程安全,获取当时线程的Looper政策,获取成功之后再经过notifyAll
办法唤醒其他线程,那哪里调用了wait
办法呢?
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.安全期
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
}面试毛遂自荐简略大方 catch (InterruptedException e) {
}
}
}
return mLooper;
}
便是getLooper
办法,所以wait的意思便是等候Looper创立好,那儿创立好之后再告知这边正确回来Looper。
24、IntentService是啥?有什么运用场景?
老规矩,直接看源码:
public abstract class IntentService extends Service {
private final class ServiceH安全期是哪几天andler exte安全教育nds Handler {
public S架构师erviceHandler(Looper looper) {
super(loopappointmenter);
}面试毛遂自荐
@Override
public void handleMessage(Message msg) {
onHandleIAPPntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHanappstoredler = new ServiceHandler(mServiceLooper);approach
}
@Override
public void on架构师和程序员的差异Start(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
ms面试技巧和注意事项g.arg1 = startId;
msg.obj = intent;
mServiceHandler.sen安全教育dMessage(msg);
}
理一下这个源码:
- 首要,这是一个
Service
- 而且内部保护了一个
HandlerThread
,也便是有无数组的界说缺的Looper在作业。 - 还保护了一个子线安全程的
ServiceHandler
。安全教育 - 建议Service后,会经过Handler实施
onHandleIntent
办法。 - 完毕使命后,会自动实施数组指针
stopSelf
连续当时Service。
所以,这便是一个app装置下载能够在子线程进行耗时使命appear,而且在使命实施后自动连续的Service。
25、BlockCana数组指针ry运用过吗?说说原理
BlockC面试必问10大问题答复anary
是一个用来检测运用卡顿耗时的三方库。
上文说过,View的制作也是面试常见问题及答复技巧经过Handler来实施的,所以假定能知道每次Handler处理音讯的时刻,就能知道每次制作的耗时了?
那Handler音讯的处理时刻怎样获取呢?
再去loop办法中找找细节:
pu面试常见问题及答复技巧blic static void loop() {
for (;;) {
// This must be in a local variable, in c架构师证书怎样考ase a UI面试技巧和注意事项 event sets the logger
Printer log安全ging = me.mLogging;
if (logging != null) {
logging.prapp装置下载intln(">>安全教育;>>> Dispatching to " + msg.target + " " +
msg.callbackapplication + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logg安全教育ing != null) {
lo架构图怎样做gging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
}
}
能够发安全期计算器现,loop架构师薪酬一月多少办法内有一个Printer
类,在dispatc数组词hMessage
处理音讯的前后分别打印了两次日志。
那咱们把这个日志类Printer
替换成咱们自己的Printer
,然后计算两次打印日志的时刻不就相当于处理音讯的时刻了?
Looper.getMainL架构图怎样做ooper().setMessageLogging(mainLooperPrinter);
public void setMessageLogg面试问题ing(@Nullable Printer printer) {
mLogging架构图怎样做word = printer;
}
这便是BlockCanary的原理。
详细介绍能够看看作者的说明:blog.zhai架构师证书怎样考yifan.cn/2016/01/16/apple…
26、说说Hanlder内存走漏问题。
这也是常常被问的一个问题,Handler
内存走漏的原因是什么?
“内部类持有了外部类的引证,也就面试是Han架构师lder持有了Activity的引证,然后apple导致无法被回收呗。”
其实这样答复是过失的,或许说没答复到点子上。架构是什么意思
咱们有必要找到那个appear究竟数组的引证者,不会被回收的引证者,其实便是主线程,这条无缺引证链应该是这样:
主线程 —> threadlocal —> Looper —> MessageQueue —> Mess安全教育渠道登录age —&面试必问10大问题答复gt; Handler —> Activity
详细分析能够看面试技巧和注意事项看我安全教育渠道登录之前写的这篇文章:/post/690936…
27、运用Handler机制规划一个数组去重不溃散的App?
主线程溃散,其实都是产生在音讯的处理内,包含生命周期、界面制作。
所以假定咱们能操控这个进程,而且在产生溃散后从头敞开音讯循环,那么主线程就能持续作业。
Handler(Looper.getMappearainLooper()).post {
while (true) {
//主线程失常阻挠
try {
Looper.loop()
} catch (e:数组和链表的差异 Throwable数组) {
}
}
}
还有一些特别状况处理,比方onCreate内产生溃散,详细能够看看架构图怎样做word文章
《能面试必问10大问题答复否让APP永不溃散》/post/690428…
总结
咱们应该能够发现,有一个问题常被问,可是全篇都没有提,那便是:面试技巧和注意事项
Hanlder机制的作业原理。
之所以不提这个问题,是因面试为要答复好这个问题需求许多常识储备,期application望屏面试常见问题及答复技巧幕前的你在读完这篇之后,再结合自己的常识库,构成自己的“完美答案”
。
Hanlder,I Got it!
参看
《Android开发艺架构规划术探求》
www.zhihu.com/question/34…
segmentfault.com/a/119000000…
/post/684490…
/post/689379…
拜拜
感谢咱们的阅读,有一同学习的小伙面试问题大全及答案大全伴能够注重下我的群众号——码上积木❤️❤️
每面试常见问题及答复技巧天一个常识点,建立无缺常识系统application架构。
这儿有一群很好的Android小伙伴,欢迎咱们参加~