前言
太久没更新会让大家觉得我是个很懒的人, 这也一直困扰着我, 学不到东西,以后怎么找工作啊, 不说了,很快就要找实习了,赶紧备些干货.
Looper
每个线程都只可以有一个Looper
Looper无非就是先Looper.prepare(),再Looper.loop()
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(); } 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; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { return; } ... ... try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } ... msg.recycleUnchecked(); } }
上面代码省略了一些打印的代码, 大家可以清晰地看到
prepare()里会new 一个Looper, 但是会先判断如果已存在Looper就抛出异常
Looper的构造方法, 创建MessageQueue和绑定当前的线程
loop方法, 最主要还是for无限循环里,每次读取一条消息,然后交给msg.target.dispatMessage方法.再回收每条消息的资源
Looper的主要作用就是
绑定当前线程,同时一个Looper也只有一个MessageQueue
loop()方法,不断从MessageQueue中取消息,然后交给消息的target属性的dispatchMessage去处理
Handler
Handler是如何与MessageQueue联系的, 而又是如何在子线程发送消息到MessageQueue的.
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) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
可以从倒数的第8和第3行看出来, Handler就这样跟MessageQueue联系上了
下面我们看看经常使用的sendMessage方法
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
最终的调用是sendMessageAtTime(…), 而刚刚好,这里有MessageQueue, 我们就很清楚地看到Handler与MessageQueue的互动
继续看enqueueMessage()方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
之前我们Looper里有写到msg.target, 这里的target在上面赋值为这个handler, 然后调用MessageQueue的enqueueMessage方法将msg插入到消息队列中
现在我们更加清楚了,接下来继续看明白dispatchMessage方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
这里出现了callback, 首先我们理清一下逻辑
如果msg.callback不为null, 就直接调用handler.handleCallback(msg)
如果msg.callback为null, 那么继续如果mCallback不为null, 并且如果mCallback成功处理消息,那么return, 否则, 调用handler.handleMessage(msg)
看看什么是handleMessage
public void handleMessage(Message msg) { }
源代码是空的, 为什么呢, 不知道大家还记不记得, 经常使用Handler的时候,都会重写handleMessage方法然后根据msg.what来进行操作
总结
- Looper.prepare方法初始化Looper,创建MessageQueue消息队列,然后使用loop方法想MessageQueue无限读取消息,回调msg.target.dispatchMessage方法
- Handler的初始化, 绑定当前线程的Looper和MessageQueue, 重写handleMessage方法, 根据msg.what进行相应的UI更新
为什么使用时没有看到Looper.prepare方法
那是因为Activity启动的时候就已经在当前UI线程调用了Looper.prepare()方法和Looper.loop()方法了
相关知识
MessageQueue
虽然叫做’消息队列’,其实是一个单链表
前面讲到msg会通过queue.嗯queueMessage()方法插入队列中, 同理还有取得下个消息的方法next(), 这里就不一一贴代码了
主要是想讲一下, 如果队列没有消息或者有延迟的消息, 这里就会阻塞.然后会回调监听阻塞的观察者
Looper如何停止
有两种方法, Looper.quit(), Looper.quitSafely(), 同种都是调用MessageQueue.quit(boolean)方法
quit() :立即回收所有消息, 这个是不安全的, 一般使用quitSafely()
quitSafely() : 回收没执行的消息
参考资料