如果想要在子线程中new Handler要做些什么准备?
简单来说就是在子线程里面初始化Looper:prepare后loop,然后构造handler的时候传入对应的子线程Looper对象。
Thread thread = new Thread(new Runnable() {
Looper looper;
@Override
public void run() {
// Log.d(TAG, "click2: " + Thread.currentThread().getName());
Looper.prepare();
looper =Looper.myLooper();
Looper.loop();
}
public Looper getLooper() {
return looper;
} });
thread.start();
Handler handler = new Handler(thread.getLooper());
上述代码可能会牵扯到一些多线程的问题,调用 thread.getLooper()的时候,此时的looper可能还没
有初始化。
这边需要引入HandlerThread的概念,这东西就是Android源码层对子线程handler的一个简单的封装:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
Handler内存泄露
这个问题不记得是哪家中厂问的了,只被问到过一次,低频考察题目(大厂估计都不屑于问这个了)。
匿名内部类持有外部Activity引用,导致内存泄漏。
如何监控handler中的消息?
这个是字节问的一个问题,我不是很清楚我回答的是不是面试官想要的。
Looper中有一个Api:setMessageLogging,会输出一个 Printer,用来打印每一条 message 消息。
如果有大佬有其他方案,欢迎评论区告知。
异步消息、同步屏障
这个也是必问题目。
线程的消息都是放到同一个MessageQueue里面,取消息的时候是互斥取消息(里面有大范围的synchronized代码块),而且只能从头部取消息,而添加消息是按照消息的执行的先后顺序进行的排序。如果有一个消息是需要立刻执行的,也是想要这个消息插队,那么就可以开启一个同步屏障,阻碍同步消息,只让异步消息通过,就是同步屏障的概念。
开启同步屏障:MessageQueue 的 postSyncBarrier()
要注意这个方法是hide方法,外部无法调用的,这个细节问题网易问过。顺带后面还问了如果我外部就是要发送一个异步消息怎么办?(不急,后边马上说)
postSyncBarrier()里面的Message 对象初始化的时候并没有给 target 赋值,因此, target == null。这样,一条target == null 的消息就进入了消息队列。
Message next()分拣消息的时候,如果发现消息队列开启同步屏障(即标识为msg.target == null),就会优先处理异步消息。
异步消息在源码中的应用
ViewRootImpl 的 scheduleTraversals()
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//开启同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//发送异步消息
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
如何外部发送一个异步消息
public Handler(boolean async)构造handler的时候选用对应的构造函数,那么通过这个handler发送的消息就都是异步的了,handler会自动给每个message添加setAsynchronous(true)。
message.setAsynchronous(true),但是这个方法需要 API 22。
IdleHandler
在 MessageQueue 类中有一个 static 的接口 IdleHanlder。当线程将要进入堵塞,以等待更多消息时,会回
调这个接口。简单点说:当MessageQueue中无可处理的Message时回调。
作用:UI线程处理完所有View事务后,回调一些额外的操作,且不会堵塞主进程。
Message next() {
synchronized (this) {
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run、Loop and wait some more.
mBlocked = true;
continue; }
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCo
}
最后现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
上述【高清技术脑图】以及【配套的架构技术PDF】点击:Android架构视频+BAT面试专题PDF+学习笔记,或者私信回复【技能提升】即可获取!
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!
Android架构师之路很漫长,一起共勉吧!