Handler和Looper的关系
使用过Handler的同学都应该知道,Handler最重要的两个方法就是sendMessage等发消息的方法和handleMessage处理消息的方法,下面就看看线程间是怎么通过Handler进行通信的。
1、Handler的默认构造方法
从中可以看到初始化了成员变量mLooper = Looper.myLooper(),mQueue = mLooper.mQueue
其实就是Looper mLooper 和 MessageQueue mQueue,mQueue就是存放Message的消息队列,同时消息队列是保存在Looper中的,至于为什么要把消息队列保存在Looper中,我们之后会进行说明。
public Handler() {
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 = null;
}
2、发送消息
sendMessage等发送消息的方法最终都会执行下面的方法,我们看到其实就是把要发送的消息Message msg和对应的发送时间uptimeMillis放到消息队列mQueue中
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
3、处理消息
那么什么时候才会处理这些发送的消息呢?没错接下来就是Looper登场了。
1)首先代码中初始化Looper me = myLooper();
这已经是第二次调用mLooper()来初始化了,所以这里多说一句,在使用myLooper()初始化前一定要调用Looper.prepare()来把Looper添加到sThreadLocal
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
看到没,实际就是从sThreadLocal中取出来的,所以用之前一定得set啊
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
2)在loop方法中我们看到有一行msg.target.dispatchMessage(msg),没错就是这里执行的。
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
//if (!me.mRun) {
// break;
//}
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
}
}
接着往下看,下面代码就会执行handleMessage来处理消息。并且如果你调用了Handler中的post(Runnable r)等方法,那么msg.callback != null 那么就会执行handleCallback(msg)
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
结论:处理消息必须要执行Looer.loop(),而执行Looper.loop()就需要先Looper.prepare(),那么为什么大多数时候我们并没有显示调用Looper.prepare() Looper.loop()呢?
主线程(ActivityThread)
1、首先看下main函数里做了什么
1)从下面的代码中可以看到,在主线程的main()方法中,调用了Looper.prepareMainLooper()和Looper.loop()
是不是很像之前讲的的Looper.prepare(),Looper.loop()?
public static final void main(String[] args) {
SamplingProfilerIntegration.start();
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
}
thread.detach();
String name = (thread.mInitialApplication != null)
? thread.mInitialApplication.getPackageName()
: "<unknown>";
Slog.i(TAG, "Main thread of " + name + " is now exiting");
}
2)看看prepareMainLooper()方法不难发现,原来这个方法中就调用了Looper.prepare()方法。
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
结论:主线程里我们并不需要显示调用,但是子线程中一定记得要显示调用Looper.prepare()和Looper.loop()
ThreadLocal
我们还记得在Looper.prepare()中调用过sThreadLocal.set(new Looper()),下面重贴下代码。
注意:每个线程只有一个Looper对象,因为每个Thread只有一个ThreadLocalMap对象并且都以key为ThreadLocal.this存储。那么在一个线程中实现多个Handler就没有意义了,因为他们都使用同一个Looper对象来保存消息。
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
而set方法实际上就是通过当前线程获得ThreadLocalMap,并把Looper放到当前线程的ThreadLocalMap中,并以ThreadLocal.this为key。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}