不知道为什么,写这篇文章的时候,不是无法上传图片,就是无法保存草稿,更郁闷的是,我都写了一小半了。firefox浏览器突然卡死重启,也没保存草稿,恢复后,啥也没了。又要重写。。。。。。。。。。。。
- handler消息传递流程
- Handler ,Looper ,ThreadLocal 源码详解及解惑
- 主线程到子线程、子线程到主线程、子线程到子线程实例演示
1、Handler消息传递流程

2、Handler ,Looper ,ThreadLocal 源码详解及解惑
2.1 Handler详解
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
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);
}
上面可以看出,Handler的各种发送消息方法。到最后,都是执行了将消息压入消息队列的方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
这里要注意,msg.target=this; 这里指明了消息的目的地为当前Handler对象,也就是说最后还由Handler来处理的。不行,待会看Looper源码就知道了。
Handler的dispatchMessage和HandlerMessage方法就不讲解了。
2.2 Looper详解
习惯了在用handler在线程想主线发消息的同学,对Looper应该比较陌生,认识他估计也是因为将Handle写错地方了,导 致报Looper没有prepare才知道有这个东西。
那么,为什么在主线程中,不需要理会Looper呢? 那是因为android太贴心了。直接给你在ActivityThread的main()方法里给你初始化好了。去看看就知道了
public static void main(String[] args) {
....................去掉不关心的
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看到,Looper先执行了prepareMainLooper(),接着执行了Loop()方法。所以,你才不用关心Looper就可以放心使用。那么在其他线程中,想要使用Handler,要不要手动去执行Looper的prepare()和loop()方法呢? 答案是必须的。必须要。
一起看Looper源码(直接主要的):
public final class Looper {
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}. 这里说了,要在调用方法后调用loop()方法。
*/
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));
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the 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;
for (;;) { //循环取消息
Message msg = queue.next(); // might block
//还记得上面说的msg.target么? 看到没?就是它,上面讲到msg.target是handler实例。
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}
看到没?loop()方法在preapare()方法说明中,被清楚的说了,要在preapare()调用后调用loop()方法。然后由loop()循环取消息。交给handler去分发。
这里还有一个点值得说下,红色代码部分,一个Thread只有一个Looer,通过这个,可以判断当前线程是否为主线程
方式为:Looper.getMainLooper ==Looper.myLooper
2.3 ThreadLocal详解
ThreadLocal 是个更神奇的东西,可以一个实例走遍所有Looper 和线程。啥意思?就是你在主线中,通过ThreadLocal的对象,取出来的Looper是主线程的。用同一个实例对象,在子线程中,调用同一个方法,取出来的是子线程的Looper . 怎么办到的?看上面Looper.prepare()方法的源码 sThreadLocal.set(new Looper(quitAllowed)); 在看set方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
原来是用一个map将thread和looper一一绑定了。
在来解惑一下:为什么Looper在那个线程,Handelr就在那个线程?
Handler其实根本不在乎自己在哪里。主要是Looper在哪个线程里。看看Handler的构造方法:
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;
}
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可以看到,如果没有指定Looper,那么Looper就是当前线程的Looper,如果指定了Looper,那就不一定是当前线程的Looper了。那么这个时候Handler所在线程就得随着Looper而改变了。下面在实例演示中可以看看。
Handler消息传递详解-主线程到子线程、子线程到主线程、子线程到子线程 (二)
源码示例下载:https://download.youkuaiyun.com/download/shoneworn/10437255