- 在没有Looper的线程,创建Handler会报RuntimeException异常,源码如下:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {//在当前线程中没有Looper会报运行时异常。
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
- 一个线程仅仅只有一个Looper,实现此功能用到了ThreadLocal,ThreadLocal是线程私有的,具体实现原理请阅读ThreadLocal的源码。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {//如果此线程已经初始化了Looper,则抛异常。
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
- 注意prepare的quitAllowed参数,此参数在子线程中为true,代表可以终止,主线程为false,代表不可以终止,当在主线程中终止,则会报异常。
void quit(boolean safe) {
if (!mQuitAllowed) {//主线程是不允许退出的,因为主线程是以消息作为驱动的。
throw new IllegalStateException("Main thread not allowed to quit.");
}
...
}
- handle中的消息用到了享元模式,建议创建Message对象的时候用Handler.obtainMessage()方法,此方法有利于防止频繁的创建Message对象造成的内存抖动,但是Message的缓存的个数最大为50个,当超过50个的message的时候,仍然会创建新的Message对象。
//android.os.Handler
private static final int MAX_POOL_SIZE = 50;
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static 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 Message();
}
-
MessageQuene采用的是单向链表的数据结构,其按照when的时间进行升序排序。
-
IdleHandler的作用是什么
IdleHandler的触发条件是,消息队列为空,或者第一条消息的触发时间还没到。所以如果屏障的超时时间还没有到,也就是目前还没有消息要处理,会触发IdleHandler
-
post和send方法都会将某个Message放到MessageQuene中,send的参数直接是Message消息,而Post是将其他类型转换为Message消息放到MessageQuene中。
-
Hander的消息派发流程,Message.callback(runnable)>Handler.mCallback>Handler.handleMessage
//android.os.Handler
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
- Handler的创建,由于Hanlder创建的线程必须存在Looper,所以创建有以下两种方式。
方式一:
class LooperThread extends Thread {
@Override
public void run() {
Looper.prepare();
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
}
方式二:
//IntentService也是利用此种方式创建Handler消息的。
HandlerThread thread_name = new HandlerThread("thread name");
thread_name.start();
Handler mHandler = new Handler(thread_name.getLooper());
创建HandlerThread可以直接用getLooper()方法获取Looper,是由于在getLooper()方法中增加了等待方法,其实起内部的实现原理与方法一类似,如下:
//HandlerThread的run()方法,开启线程的时候调用。
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
//此方法用来等来Looper的创建并且返回。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
- 分析loop()方法
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
//此方法可能会阻塞,造成阻塞的原因是next()方法中的nativePollOnce(),唤醒实在消息队列enqueueMessage方法中的nativeWake,此处用到了epll机制,类似java的wait(),notify()方法。
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
}
}
-
消息屏障,Message分为3中:普通消息(同步消息)、屏障消息(同步屏障)和异步消息。在Android系统中存在一个VSync消息,它主要负责每16ms更新一次屏幕展示,如果用户同步消息在16ms内没有执行完成,那么VSync消息的更新操作就无法执行在用户看来就出现了掉帧或卡顿的情况,为此Android开发要求每个消息的执行需要限制在16ms之内完成。但是消息队列中可能会包含多个同步消息,假如当前主线程消息队列有10个同步消息,每个同步消息要执行10ms,总共也就需要执行100ms,这段时间内就会有近7帧无法正常刷新展示,应用执行过程中遇到这种情况还是很普遍的。
Android系统中的异步消息就是专门解决消息处理延迟的问题,它需要配合同步屏障(SyncBarrier)一起工作,在发送异步消息的时候向消息队列插入同步屏障对象,消息队列会返回同步屏障的token,此时消息队列中的同步消息都会被暂停处理,优先执行异步消息处理,等异步消息处理完成再通过消息队列移除token对应的同步屏障,消息队列继续之前暂停的同步消息处理。