前言:
我接触Handler第一次的时候就比较懵逼,Handler handler=new Handler()然后调用handler.sendEmptyMessage();就可以发送消息了,然后在Handler的回调中处理消息.当时只是单纯觉得是一个消息队列,从这边发送消息,那边是一个死循环接收消息,然后调用回调函数打印.仔细没多想,现在具体想了一下,看了源码,才知道并不是那么简单.
那么具体那些问题需要思考呢?
1.队列到哪里?谁又在取消息分发?
2.死循环到底怎么一个循环法.
3.还有很多人误解的为什么主线程不会因为Looper.loop()里的死循环卡死?
…
带着这些问题,我们今天就具体看看源码怎么说
Looper
我们知道Looper类是一个线程的消息循环处理器
1.Looper构造方法私有.
2.Looper对象每个线程只能有一个.
3.并且通过静态prepare方法创建.
4.保存在ThreadLocal<Looper> sThreadLocal
中(是一个线程有关的键值对存取容器)
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
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));
}
我们下来看看Looper类的loop方法
public static void loop() {
final Looper me = myLooper();//得到当前线程的looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//从looper中拿出消息队列
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); //进行遍历消息队列
if (msg == null) {
return;
}
Printer logging = me.mLogging;
msg.target.dispatchMessage(msg);//拿到Handler进行分发事件
final long newIdent = Binder.clearCallingIdentity();
msg.recycleUnchecked();
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
loop()中就做了4个事情
1.得到当前线程的looper
2.从looper中拿出消息队列
3.进行遍历消息队列
4.拿到Handler进行分发事件
这里思考一个问题:既然知道ThreadLocal<Looper> sThreadLocal
是一个拿取当前线程的Looper类,那么当前线程是在哪?
这里看下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;
...
}
可以看出来我们一般使用在Activity中创建Handler然后发送消息,所以Handler中得到的也是Activity的线程.
问题来了:Activity的线程大家都说是UI线程,但是也没有人具体说怎么UI了,在哪里UI了,下面我就带大家溜溜源码.
图片出自Android系统大牛Gityuan:Activity启动流程篇:
http://gityuan.com/2016/03/12/start-activity/
具体我们看一看目标进程中的哪里创建了Activity对象
//ApplicationThread.java
public final void scheduleLaunchActivity(...) {
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
...
handleLaunchActivity(r, null);
} break;
...
}
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity a = performLaunchActivity(r, customIntent);
...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//通过反射创建Activity
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
//下面就是调用各种Activity的生命周期回调方法
activity.attach(...);
mInstrumentation.callActivityOnCreate(activity, r.state);
activity.performStart();
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,r.persistentState);
mInstrumentation.callActivityOnPostCreate(activity, r.state,r.persistentState);
mInstrumentation.callActivityOnPostCreate(activity, r.state);
return activity;
}
上面过程我们看出来是ApplicationThread类sendMessage(H.LAUNCH_ACTIVITY,r);在handleMessage的分发事件中创建出来了Activity对象,所以这个问题归结于这个分发事件在那个进程的那个线程中跑.
来看,首先发给消息的Handler是在ActivityThread类中创建的H对象
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
也就是说,在Activity中的Looper对象是在ActivityThread所在的线程中.
那我们就来看看ActivityThread在那个线程中,我们看看ActivityThread创建的main方法
public static void main(String[] args) {
...
Looper.prepareMainLooper();//创建属于此线程的Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
}
public static void prepareMainLooper() {
prepare(false);
...
}
private static void prepare(boolean quitAllowed) {
...
sThreadLocal.set(new Looper(quitAllowed));
}
到了这里我们惊喜的发现在ActivityThread的main()方法中创建了主线程的Looper,并且Activity和ActivityThread在同一个线程,即主线程
总结:
1.Looper类是Android中线程消息通信的重要类,扮演线程消息的处理器的角色
2.每个线程只能创建一个Looper对象
3.通过Looper.prepare()方法创建Looper对象,Looper.prepareMainLooper();创建主线程Looper对象
4.有了Looper对象用loop方法进入消息循环
5.loop方法不断从MessageQueue队列中拿出消息,然后分发给Handler的回调方法
6.一个Looper可以对应多个Handler对象
7.Looper方法在存取每个线程所属于的私有变量是通过ThreadLocal成员
8.在Activity中创建的Handler对象,中创建的Looper是和ActivityThread在一个线程中即主线程
下一节我们分析Handler,Message等其他有关重要的类