一、生产者与消费者
Android开发中,经常在子线程中进行一些操作,当操作完成之后会通过Handler发送一条消息给主线程,通知主线程做出相应的操作,其背后原理,是一个经典的生产者与消费者模型,生产者和消费者在同一时间内共用同一个存储空间,生产者往存储空间中添加消息,消费者从存储空间中取出消息。如下图所示,这个是Handler工作的基本原理。
二、为什么主线程创建Handler不用调用Looper.prepare() Looper.loop()
因为在我们APP启动的时候,系统已经帮我们调用了。
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
// 初始化Looper以及MessageQueue
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();// 开始轮训操作
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper.prepareMainLooper();
初始化Looper,MessageQueue以及和当前线程绑定起来
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
prepare()方法,主要是把当前线程与Looper绑定起来,并且保证一个线程只有一个Looper
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));
}
Looper的构造方法中创建了,当前线程的MessageQueue,也只有一个,同时保证了一个线程也只有一个MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper.loop()
public static void loop() {
final Looper me = myLooper();// 通过ThreadLocal获取刚才创建的Looper
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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {
// 这是一个死循环不停的从消息队列中取消息
Message msg = queue.next();
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// 取出消息,交给Handler的dispatchMessage取处理
msg.target.dispatchMessage(msg);
// 处理完成之后回收消息
msg.recycleUnchecked();
}
}
三、创建Handler
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
内部调用this(null,false);
public Handler(Callback callback, boolean async) {
// 获取Looper,注意不是创建
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//创建消息队列MessageQueue
mCallback = callback; //初始化了回调接口
mAsynchronous = async;
}
从ThreadLocal中获取Looper
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
四、创建Message
可以直接new Message 但是有更好的方式 Message.obtain。因为可以检查是否有可以复用的Message,避免过多的创建、销毁Message对象,达到优化内存和性能的目的。
这块用到了,享元设计模式,避免内存抖动。
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();
}
五、Message和Handler的绑定
创建Message的时候可以通过 Message.obtain(Handler h) 这个构造方法绑定。
当然可以在 在Handler 中的enqueueMessage()也绑定了,所有发送Message的方法都会调用此方法入队,所以在创建Message的时候是可以不绑定的。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// message 和 Handler进行绑定
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler发送消息的方法很多,但是最终都会调用,MessageQueue的enqueueMessage方法进行入队操作。最终由Looper取出,交给Handler的dispatchMessage进行处理。
public void dispatchMessage(Message msg) {
// callback在message的构造方法中初始化或者使用
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 最终执行handleMessage方法
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
六、总结
handler.sendMessage 发送消息到消息队列MessageQueue,然后looper调用自己的loop()函数带动MessageQueue从而轮询messageQueue里面的每个Message,当Message达到了可以执行的时间的时候开始执行,执行后就会调用message绑定的Handler来处理消息。大致的过程如下
七、消息屏障
概念:就是 msg.target 为null的消息,用于屏幕刷新(60hz的屏幕,需要每16.6ms去刷新一次,这些消息,需要及时处理,不能和其他的消息类比,)
private int postSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;// 这块没有给msg.target 赋值
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
八、异步消息
异步消息会设置 msg.setAsynchronous(true);
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();// 先发送消息屏障
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);// 然后发送异步消息
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
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);
}
}
}
九、消息屏障及异步消息处理
在取消息的时候,先找到消息屏障的msg,然后再找到异步消息去处理,最后移除掉消息屏障的消息
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) { // 消息屏障的msg
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous()); // 循环寻找异步消息,然后处理屏幕刷新
}
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);// 移除消息屏障
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);// 移除异步消息
}
}