借鉴自http://blog.csdn.net/lmj623565791/article/details/38377229/学着鸿洋理一遍
Handler
Looper
Message
Looper.prepare()
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)); }
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();这个东西说来话长,用一句最简的话就是,他相当于一个Looper的成员变量,不过是线程绝对安全的,就算有100万个线程同时访问这个类,他也不会出现数据错乱的情况。如果还想深究的话可以看看 http://blog.csdn.net/qq_36523667/article/details/78877176(深入理解ThreadLocal)
我们由于调用的是空参的,所以这个quitAllowed就默认是true
public static void prepare() { prepare(true); }
所以一句话,mLooper.prepare()方法等于是给当前的Looper设置了一个成员变量Looper实例。并且确保了他最多只有一个Looper实例被维护在Looper类里。
既然new了一个Looper给他自己和线程,那么肯定得看看构造方法吧,看看new出来些什么,以及一个Looper对象最基本具有的东西。
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }一个消息队列(quitAllowed是消息从队列中可移除的意思)。再把Looper所属的线程维护给Looper自身。
mLooper.loop()
代码很长,梳理下逻辑
1.获取我们在prepare中new的那个looper
2.再根据我们取出来的这个looper获得他在构造函数中new的消息队列
3.无限循环
仔细讲讲这个无限循环
不断从消息队列中去取消息,队列为空,没有消息可取,就return,队列就阻塞了。
如果不为空,取出来了。怎么处理呢?主要是这句话msg.target.dispatchMessage(msg);交给msg的target去处理,target就是Handler的实例。他就是通过这个方法来一级级分发,正常情况下是执行你自己定义的回调操作。
最后释放资源
Looper的几个方法的作用合起来总结一下:
prepare,弄出一个消息队列,loop,无限去从消息队列中取消息。
刚刚提到了target就是Handler的实例,那么讲讲Handler。
先看构造方法
public Handler(Callback callback, boolean async) { //... 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; }先取得当前线程内的looper,再把looper的消息队列赋给Handler自己来维护。
接下来我们平时发消息的操作都是sendMessage。。。不管以何种形式发送,最终都会调用sendMessageAtTime方法
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); }注意在Looper类中采用了ThreadLocal中来保证线程安全的,ThreadLocal传入的参数是Looper,所以整个Looper对象都是线程安全的,所以Looper对象维护的消息队列也是线程安全的。所以这个sendMessageAtTime方法采用的是成员变量赋值给局部变量来保证线程安全。
最后调用了enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }这里就得知了,handler就是target。
所以看一下一开始提到的dispatchMessage方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }正如我上面所说的,经过一系列分发,执行handleMessage,而它就是一个交给子类去实现的空方法。
空方法
public void handleMessage(Message msg) { }
一般会这样重写
private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case value: break; default: break; } }; };
最后还有一个常见的post方法的使用
Handler handler; new Thread(new Runnable() { @Override public void run () { try { Thread.sleep(1000); handler.post(new Runnable() { @Override public void run() { mTest.setText("post");//更新UI } }); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();handler.post直接就可以更新UI,这值得深思。其实到最后还是会执行上面的dispatchMessage方法。不过不再是执行那个handleMessage方法了,而是执行了handleCallback方法。直接就调用了Runnable的run方法,实现了UI的更新。而这个run是在handler所在的线程执行的。这里自然是在主线程了。因为handler是在主线程new的。handler.post等效于
private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case value: break; default: break; } }; };
下面来追溯下为什么会这样
看看post的源码
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); }
我们先看一下getPostMessage方法
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }这里直接就把这个Runnable赋给Message的callback了,记牢了!(此外最好用obtain来新建message对象,涉及到缓存机制)
然后追溯sendMessageDelayed下去,发现最后还是执行了enqueueMessage方法
把handler赋值给了message.target。private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
所以我们再看一下dispatchMessage方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }上面让你记牢的那个点,msg是有callback的,所以在这个向下分发的过程中,在第一阶段就被拦截下来了(因为callback不为空)。
最后看看handleCallback方法
private static void handleCallback(Message message) { message.callback.run(); }运行了。
最后梳理下流程
在主线程中new一个handler,handler获取activity中封装的本来就有的looper,以获取消息队列。所以新建的子线程也根部不需要写looper。再调用sendMessageAtTime,把msg.target标记为这个handler,再把这个msg入消息队列(enqueue方法)。然后looper.loop就一直在取。取出消息,最终会调用msg.target.dispatchMessage,最后执行一个交给子类实现的方法。
接下来就是鸿洋没讲的一点了。他这个Looper获取的方式。是通过判断你当前线程在哪个地方,再来获取的。所以无疑,activity中的looper是封装在主线程里的。所以我们的消息操作都是在主线程里的looper里的消息队列里进行操作的。
所以你如果期望主线程向你子线程发送消息的话!那就要在子线程里指定looper,让handler发送到你子线程里的looper里来,而不是主线程里默认封装就有的那个looper!
就像这样
class MyThread extends Thread{
private Looper looper;//取出该子线程的Looper
public void run() {
Looper.prepare();//创建该子线程的Looper
looper = Looper.myLooper();//取出该子线程的Looper
Looper.loop();//只要调用了该方法才能不断循环取出消息
}
}
mHandler = new Handler(thread.looper){
public void handleMessage(android.os.Message msg) {
Log.d("当前子线程是----->",Thread.currentThread()+"");
};
};
跑题了。继续梳理。还有一个情况就是post,post就会调用sendMessageDelayed(getPostMessage(r), 0)方法。一方面里面的getPostMessage(r)是在里面new了一个message出来,并把这个runnable赋给msg.callback。一方面外面最终又会调用sendMessageAtTime,把handler赋给msg.target,并把message放入队列中。最后会在loop在取的时候,执行msg.target.dispatchMessage方法,因为有callback,直接就执行了这个runnable了(runnable.run)。
图解
post是执行了这一句sendMessageDelayed(getPostMessage(r), 0),传递了r为callback