第一次写博客,没有别的目的,就是把自己理解的知识进行一个梳理,方便下次需要的时候不用到处去找.
要理解handler 机制需要知道这几个类,简单的介绍下
1,handler 用于线程之间切换,发消息 处理消息(类似一个快递员,收快递,发快递)
3,Message 一个消息对象,他有个tag,还有个object,还有两个args(可以把它理解为一个快递包装起来了,tag就是它的收件人名字,我们发了一百条消息,当handler 收到的时候根据tag 去区分它们都是做什么用的,object,和args1 代表它实际的货物,也就是我们要传过去的data)
3,MessageQueue 见名知意 一个消息队列(其他它内部并不是队列实现的,而是一个链表,不过你可以这样理解,它就是一个快递仓库,里面有各种各样的货物(message))
4,Looper 一个阻塞式轮询器,它作用就是不断的从MessageQueue中拿出来消息,然后给分发给对应的handler(类似一家快递公司,不断的去看仓库(MessageQueue)是否有快递发货(message),如果有马上把快递(message)拿出来,发给对应的快递员(handler))
简单介绍了下,不要认为我送过快递,我没做过快递员,当然我不鄙视任何职业,只是为了方便理解,ps(我记知识的方法,会把这一套逻辑联想为一套自己已经熟悉的逻辑,下次想的时候想起自己熟悉的逻辑就知道了)
进入正题
handler 直接看一下没有参数的构造方法,无参调用有参,无论调用哪个构造方法最后都会走到这里
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;
}
这块代码我们只需要关心第11 行之后, 这个大概意思呢就是 一个快递员(handler) 创建,必须要给她一家快递公司挂名啊(looper),
然后公司(looper)把管理的仓库(持有的MessageQueue)交给这个快递员(handler),
Looper.myLooper();
至于公司怎么创建先不需要关心,等下会说,
我们只需要明白这个方法过后 快递员(handler)有公司(looper),有仓库(MessageQueue),这样才能发送快递呀.这里边有一个非空判断,很好理解 假如说没有这个快递公司,其他都是白扯 只能让程序停止了,下面有好多类似的判断在这里一带而过,不再多做解释.
ok,下面我们看发快递(发消息)的方法
sendMesssage 一系列的方法和 post一系列的方法 内部最终实现都是这个方法sendMessageAtTime()
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
这个方法很简单快递员(handler)发货之后,不能每个快递员(handler)都有自己的发货方式,A发的只有货物,B发的货物,还说要晚两天发,这样人家很难管理所以要做到统一对接,走一个正规的流程.
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
注意2行,,货物需要登记,不是直接扔仓库就完了,出事了以后还得找人负责呢,所以通过货物(Message)的tag ,这里把当前的快递员(handler) 做了一个登记
再看第6行,这就是一个货物(Message)入库的方法,我们去看下源码
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
这段代码有好多东西是很难看得懂的,但是这个并不影响我们对这个方法的理解,(ps我感觉他写的很复杂,一点都不通俗易懂)
大概意思就是把货物(Message)入库,进行处理,根据发货时间排序一下.
1MessageQueue队列里边只保留一个Message对象,
2刚发过来的Message对象和之前持有的Message比较,根据发送延迟时间排列一下(持有那个延迟最低的那个Message),
3,把多余的对象通过Message对象自己内部的Next连接起来,简略的说把Message对象通过next方法连接起来,然后根据时间顺序 排序一下.
到此为止,消息已经从子线程的handler对象发送到消息中并且按时间顺序排好
再看最后一个公司(looper)类 先看构造函数
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
可以的到两点有用的信息1,每个公司(looper)对象会创建一个仓库(MessageQueue对象)2,每个公司(looper)会持有当前的线程对象(这里标记一下)
再看最重要的流程
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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
大概意思就是公司(looper)对仓库(MessageQueue)里面的货物(Message)进行处理,也是整个环节中比较重要的流程,你想如果一直收货(接受Message)却不发货(处理Message) 仓库(MessageQueue)终会爆棚,现在说一下具体怎么处理的
主要看13行之后,开启了一个阻塞式死循环,ps这个我解释不了,只你告诉你这么记了,他的功能基本上就是无限循环检查仓库(MessageQueue)是否有货物(Message),如果有看第36行,
msg.target.dispatchMessage(msg);
根据货物(Message)的tag(handler) 去把货物(Message)分发出去,发到快递员(handler)内部去处理,至此又把货物(Message)发回给快递员(handler对象),只不过在这个过程已经切换了线程, 多条线程操作一条仓库(MessageQueue).
我们再去看一下快递员(handler)怎么处理的
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这个方法这样理解,消息本身有回调优先级最高,最先回调,然后再是handler对象的callback (这个从上边构造函数的时候可以看到在哪里赋值)优先级第二, 最后才是自己的handMessage方法被回调,优先级最低.
其中有两个问题我们还没说,现在开始解释
第一 公司(looper对象)的创建,看源码可知,构造方法私有,只有内部调用看到这个方法
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));
}
这个方法首先是一个判断,如果get到的对象不为空 就抛异常,大概意思你要创建公司(looper),我先判断你这个公司是不是存在,存在直接告诉你不行,有这个公司了,如果没有这个公司,我就给你创建,然后在我这边登记一下,结论 每个线程只能有一个looper对象.(重点标记)SthreadLocal 这个对象可以把它理解为一个map集合,那么key是什么呢,聪明的人应该能知道了,就是CurrentTread,下面验证一下
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
看到这里就差不多了,ps(看深了容易乱,就像你知道1+1=2,却不知道为什么等于2 ,这个不是我们研究的,这个是科学家去研究的,如果想当科学家的另当别论)
这个类就相当于公司登记,利用一个map集合,当前线程做Key,公司(Looper)对象做为值保存,方便获取和存储,至此我们基本上明白了,(ps回看一下handler的构造方法 获取looper ,你发现就是这样获取looper对象的,)
最后总结一下
1Looper构造方法私有,必须调用 prepare()方法才能创建出来否则 looper对象就是空的,你创建handler的时候就会抛异常(回看上边)
2,Looper创建的时候还需要先验证一下是否存在(根据当前线程做Key去验证),所以每条线程只允许创建一个looper对象,由于MessageQueue对象是在looper对象构造方法创建的可知,每个looper只有一个MessageQueue,也就是每个线程只有一个队列,
3,handler 和Message可以有多个
小知识
View.Post() 方法 activity.runOnUiThread()方法,handler.post ()
都是用的handler机制sendMessage()实现的线程切换,喜欢的自己去看源码
最后画张图看一下