本文我们主要是要介绍Handler机制,但是涉及到Handler又不得不介绍Message,MessageQueue,Looper,Handler机制主要是依赖后面几个的,所以我们在文中会一次介绍到他们几个。
通过本文你可能会了解到一下几点
1.Handler机制及Handler与Message,MessageQueue,Looper的关系
2.Handler在子线程中的应用及原理
3.Message的复用机制
4.为什么主线程可以有死循环(loop())
Handler源码位置:
android\frameworks\base\core\java\android\os\Handler.java
首先看他的构造:
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
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;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
一般我们都用的是无参的构造。先说一下那个Callback,他是一个接口:
public interface Callback {
public boolean handleMessage(Message msg);
}
这是处理消息的一种手段,一般我们也很少用,因为我们都重写了handleMessage方法,效果一样的,我们主要从无参构造这条线看下去。
在无参构造中,直接调用了参数类型为Callback 和boolean 的构造。这里面他给Looper赋值为Looper.myLooper()。来看一下这个方法:
Looper源码位置:
android\frameworks\base\core\java\android\os\Looper.java
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
static final ThreadLocal sThreadLocal = new ThreadLocal();
这个方法实际上就是获取当前线程的looper,ThreadLocal是Java的lang包中的类,他的set方法是在当前线程中保存一个对象,get是从当前线程中取出那个对象。这里存取的就是Looper。但这个Looper在哪存的呢?还是从源码中找答案:
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));
}
有些人看到这应该就明白了,这里也给出了另一个问题的答案,为什么在子线程中使用Handler或者Toast时要先调用Looper.prepare()。原来这个方法有一个重要的作用就是给当前线程设置Looper,如果不设置,就是null,当然会有问题。但为什么主线程中不需要呢?
这个问题要从app的创建说起,但具体的app启动流程这里就不详细叙述了,只说明一点,在启动app的进程时,Zygote会通过socket接受AMS的请求,通过反射的方法调用ActivityThread的main方法,ActivityThread也就是一个应用的线程,也就是主线程,我们看一下这个方法:
public static void main(String[] args) {
....
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
....
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
这里调用了prepareMainLooper方法,它和prepare有什么区别呢?直接看源码:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
可见prepareMainLooper也是调用了prepare,只有参数的差别,一个为false一个为true。这个参数最后用到了Looper的构造上:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在构造上又传给了MessageQueue。这个参数quitAllowed的作用在MessageQueue中很清楚:
android\frameworks\base\core\java\android\os\MessageQueue.java
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
....
}
只在这里用到了上文中的参数quitAllowed,也就是为true时,会报异常,异常也很清楚,就是主线程不允许调用quit退出,这个值只在调用prepareMainLooper方法时为true,我们用的时候都是调用prepare方法,也就是为false。
这里做一个小结,Looper.prepare()最主要的作用是初始化Looper,而Handler是基于Looper,一个线程创建后是没有Looper,主线程也不例外,要想使用Handler就必须初始化,一般线程调用pr