1.Handler是什么?
Handler机制主要为线程间通信而生,是Android中定义的一套消息传递机制。
主要是为了解决子线程执行完耗时操作后,怎么回调到主(UI)线程的问题。
2.Handler机制的主要成员有哪些?
Handler、Looper、Message和MessageQueue
Handler:负责发送Message到MessageQueue,同时负责接收消息
Looper:负责从MessageQueue读取消息,并通过Message的target,调用handler的消息分发处理
Message:消息载体
MessageQueue:消息队列
3.handler消息机制的主要流程是什么?
消息发送过程:Handler在子线程发送Message,由于Handler初始化的时候有持有当前线程的Looper和Looper中的 MessageQueue,而这个Handler在主线程初始化,也就是该Handler持有主线程Looper和MessageQueue,发送普通消息会给 Message的target赋值Handler本身,发送消息会最终会调用MessageQueue的enqueueMessage方法。
消息插入过程:根据系统相对时间+延迟时间 按照顺序 插入到单链表MessageQueue中,如果在表头,会判断是否有阻塞,有 阻 塞会调用native层的nativeWake方法唤醒线程,如果在表中间或表尾会判断该消息是否是异步消息,且阻塞的话,也会调用 native层的nativeWake方法唤醒线程。
消息取出过程:Looper循环loop方法,会调用MessageQueue的next方法,这个方法在源码上面显示有可能会阻塞, MessageQueue next 也有一个死循环操作,如果上一个取出的消息有阻塞时间,会先调用native层的nativePollOnce方法进行 阻塞,然后会判断是否是屏障Message,如果是屏障消息先过滤掉普通消息,先获取异步消息。如果Message消息的when大于 当前系统相对时间则会设置需要阻塞的时间,如果Message消息的when小于或者等于当前系统相对时间,会取出这个消息。如 果有阻塞的情况,还会调用IdleHandler的回调。通过MessageQueue取出Messgae后,会通过Message的target(target就是发 送该 Message的Handler)调用 Handler的dispatchMessage方法处理消息分发。
消息分发过程:如果Message callback不为空,代表是通过post的方式发送消息,调用Runnable的 run方法;如果Handler中的 mCallback不为空,调用mCallbcak的 handleMessage;否则会调用handleMessage回调。
4.延时消息的实现 是在插入MessageQueue的时候,还是Looper取的时候?
取消息的时候实现的!
插入的时候会根据相对时间+延迟时间作为message的属性,并根据该属性进行排序。
真正的延时是在Looper取消息的时候进行判断是否为延时消息,然后调用native层的nativePollOnce方法进行阻塞。
5.发送消息用send 和 post 有什么区别?
send方式和post方式本质没有区别,都是发送Message,只不过post方式会把Runnable对象赋值给Message的callback,在 最后消息分发的时候会回调Runnable的run方法。
6.为什么建议用obtain方法创建Message?
Message 本身包含两个Message对象,一个是sPool,一个是next,但通过看源码可知道sPool是一个static对象,是所有对象共 有,Message sPool就是一个单链表结构,Message就是单链表中的一个节点。
使用obtain方法,取的是Message 的 sPool ,改变sPool指向sPool的next,取出sPool本身,并清空该Message的flags和next。 这样的好处是是可避免重复创建多个实例对象,可以取消息池子之前已经存在的消息。
7.子线程能直接新建Handler并使用吗?
(1)直接创建会报错!
在创建Handler方法中,Handler会持有该线程的Looper 和 Looper中的MessageQueue,Handler的使用必须是结合 Looper,而子线程中并没有绑定Looper,所以会报错。
因为Handler的构造方法中可以传递Looper:handler对象所绑定的线程其实并不取决于该handler对象由哪个线程构建,而 是取决于该handler对象所绑定的Looper属于哪个线程。
handleMessage 方法执行的线程一定是在创建Handler的线程吗?答案是否定的,是在绑定Looper所属于的那个线程。
(2)想要创建需要干嘛
1. 在创建Handler前首先调用Looper.prepare()创建Looper
2. 然后调用Looper.loop()开启循环(只要保证发消息之前调用过该方法即可,否则Looper不运转,
注意:不必纠结这一步是在new Handler前 还是在 new Handler后)
两步缺一不可!
8.Looper是如何确保一个线程只能创建一个的?MessageQueue呢?
1. 利用 ThreadLocal特性。(1)判断ThreadLocal里面是否为空(2)把Looper放到ThreadLocal中,
2. 利用私有构造方法 只能在类里面被访问,无法被类外访问。
3. ThreadLocal 的详细解释
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
9.HandlerThread和普通线程有何区别?
其实就是一个自己封装好Looper的线程,源码如下
构造方法:
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
run方法:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
10.Handler同步屏障
(1)Message消息主要分为三种:同步消息、屏障消息、异步消息
(2)同步屏障就是通过屏障消息来屏蔽所有同步消息,处理后续异步消息
核心代码:
首先是 MessageQueue 取消息的代码:
@UnsupportedAppUsage
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
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(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
最核心的是的判断是这段代码:
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
屏障消息主要是起一个屏蔽作用,所以不需要有handler 处理消息分发,所以target为null。
如果有屏障消息,且消息不是异步的则继续取下一个,直到遇到异步消息。
异步消息如何设置?:
(1) 可以直接调用Message的setAsynchronous方法
public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}
(2) Handler的构造方法也可以设置 mAsynchronous,但是是hide标签修饰的方法,我们可以通过反射去调用,也是可以的。
同步屏障的应用?:
比如:屏幕刷新机制
Android 每隔16.6ms会刷新一次屏幕,每个Activity对应一个 DecorView 根布局View树。
初始化过程中DecorView会被添加到viewRootImp(根视图);
根视图setView的过程:
viewRootImp.setView() —>
viewRootImp.requestLayout() —>
viewRootImp.scheduleTraversals() —>
viewRootImp.doTraversal() —>
viewRootImp.performTraversals()—>
主要看scheduleTraversals这个方法:
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//设置同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//发送异步消息
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
其中“ mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); ”这行代码就是设置同步屏障。
然后咱们对这行代码进行跟踪:
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
@TestApi
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
@TestApi
public void postCallbackDelayed(int callbackType,
Runnable action, Object token, long delayMillis) {
if (action == null) {
throw new IllegalArgumentException("action must not be null");
}
if (callbackType < 0 || callbackType > CALLBACK_LAST) {
throw new IllegalArgumentException("callbackType is invalid");
}
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
到最后发送了一个异步消息。
因为 同步屏障的作用,所以 异步消息的执行优先于同步消息,保证了屏幕刷新的及时性和优先性。