您的位置:首页 > 移动开发 > Android开发

Android系统Handler消息处理机制(一)

2017-02-28 22:29 501 查看

前言:

我接触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等其他有关重要的类
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 源码