简书链接:handler的dispatchMessage方法是如何被调用的探索mtarget是如何被附加上handler的
文章字数:1036,阅读全文大约需要4分钟
首先来点基础描述:
主线程的handler的looper,也就是Loop.getMainLooper()返回的loop,默认在ActivityThread类的main方法初始化了 ,在main方法里面调用了Loop.perpareMainLoper();初始化了一个loop,所以一般主线程的looper实际上就是那里初始化的looper 具体ActivityThread类的main```代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

public static void main(String[] args) {
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}

// End of event ActivityThreadMain.

Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");
}
}

创建了一个默认的loop又维护了一个messageQuare主线程的looper轮训方法loop()是早早就被调用了的,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();

for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {

return;
}



try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}

if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}


final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {

}

msg.recycleUnchecked();
}
}

那么handler类里面的dispatchMessage触发是因为添加到消息队列中的消息Message类的``target被设置了handler,然后在Looper类的loop方法里面处理这个消息的时候触发,也就是下面的这句代码 msg.target.dispatchMessage(msg);```

1
2
3
4
5
6
7
8
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}

1
2
3
4
5



Looper相关方法
构建loop静态对象 保证一个线程只有一个

public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException(“The main Looper has already been prepared.”);
}
sMainLooper = myLooper();
}
}

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));
}
1
2
至于```Looper.loop()```方法上面已经贴过了,也就是开启轮训,当没有的时候cpu进入等待。这个和某个**酷Q机器人**易语言源码当中的消息处理惊人的相似。他那个差不多就是消息队列的死循环,没有的时候就进行睡眠,然后有消息的时候线程唤醒。
里面用到了```ThreadLocal```通过线程名作为键,保证了一个线程只有一个```ThreadLocal```一个```Looper```
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
1
2

ThreadLocal的关键方法
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
1
2
3
4
5
6

源码太深,这里只讲如何被设置上去的,
根据handler的源码分析,```post``` ```postDelay```实际上都最终调用了```sendMessageAtTime```然后调用了
``` return enqueueMessage(queue, msg, uptimeMillis);```

那么继续,先看看handler的一些方法,
public final Message obtainMessage()
{
    return Message.obtain(this);
}

public final Message obtainMessage(int what)
{
    return Message.obtain(this, what);
}


public final Message obtainMessage(int what, Object obj)
{
    return Message.obtain(this, what, obj);
}
1
2
这里都把```handler```传递进去了
```Message```的obtain方法设置了 ```m.target```

public static Message obtain(Handler h, int what, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.obj = obj;

    return m;
}
1
既然是这样的,那么自己创建一个纯message类会触发吗?

Message message=new Message();
message.what=1;
message.obj=”测试纯message”;
handler.sendMessage(message);

1
2
3
结果令人震惊,还是触发了,这```message.taget```他是如何被设置的呢?

然后又看了看,原来那报错的红色代码没有被我注意到,也就是说追踪走的```sendMessageAtTime```方法走的```enqueueMessage```方法中强制给message的targer设置了handler为自己。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
这句话明显的写这句话``` msg.target = this;``` 所以 明白为什么可以回调了,ok讲解完毕,知其然也知其所以然了。

### 其它相关
1、```handler```类的```queue```成员变量是从Looper中获取到的,handler发消息实际上是拿到```Looper```里面的静态消息队列字段
``` mLooper.mQueue```


2、而``` mQueue = new MessageQueue(quitAllowed);```也就是消息队列对象的初始化是通过```prepare```的调用导致```    sThreadLocal.set(new Looper(quitAllowed));```这句代码被执行,然后导致```Looper```构造方法执行,然后触发这个队列的初始化。···``` mQueue = new MessageQueue(quitAllowed);```···

```sThreadLocal```也就是```ThreadLocal```默认在成员变量就初始化了```sThreadLocal```而且是静态的 这个字段也是放到```Looper```类里面存起来的
3、真正负责处理消息的是在```looper()```开启一个死循环for,不断的0调用```MessageQueue```的```next()``` 知道返回null才终止,,在这个方法几乎是没法出来了,永远卡在这个方法,除非满足特定条件,`比如```messagequare```的```quit```方法被调用。
4、```looper```的```looper```死死循环外,消息队列```MessageQueue``` ```next```也嵌套了一个死循环,所以即使消息没有也不会进行立马返回,而是等待,只有当有消息的时候才返回给```looper()```处理这里面主要做一些时间的处理,比如那些延时时间发送的。


有些东西还是没法理解,深度对我来说还是遥不可及