先看一下源码中对looper进行的解释,
根据注释内容,可以了解到,消息循环的交互情况都是通过handler进行的。
再不和handler搭配的情况下,通常都是以looper.prepare和looper.loop这种方式成对出现的,使在这两句话中间执行的内容都是通过looper进行通信执行相应内容。
此类还有对api实施进行注释描述,贴上来也一起看一下吧。
这部分描述可以看到,looper基于MessageQueue并可以影响任务队列的状态。通常都是在MessageQueue或者Handler上进行定义,这里讲了looper的作用和其定义的时机。
个人理解:
looper通常都是在非主线程的时候使用让部分代码块可以作用在主线程,进行ui更新等一些操作。用到的地方有很多,在activityThread当中可以看到很多looper的影子。在什么时候用源码的注释上面解释的挺清晰了。
该类中中在跨进程部分运用的都是binder进行通信,threadlocal进行线程管理。
此类中不对外暴露的方法不进行介绍。
----------------------------------------------------------我是分割线----------------------------------------------------------
prepare()方法最终会传递true到 prepare(boolean quitAllowed)方法当中,这里直接看 prepare(boolean quitAllowed)方法。
这里可以看到该方法会优先判断threadlocal线程池里面是否为null,里面有数据的时候就会抛出运行异常(因为代表这个时候looper有正在运行,必须要保持一个looper),里面没有数据的话就会把传递过来的boolean类型放到looper对象的参数中,然后设置到线程池里去运用。
getMainLooper方法,会锁住looper类,然后返回当前正在使用的looper。
myLooper()方法,会从当前的threadlocal获取内容并进行返回。
showSlowLog(long threshold, long measureStart, long measureEnd,String what, Message msg)方法,传递过来的参数如果还在倒计时,那么就打印log并返回为true,打印的log内容见下图:
myLooper()方法,会获取当前threadllocal里面的内容进行return。
myQueue()方法,执行mylooper方法获取其mQueue变量进行retun。
Looper(boolean quitAllowed)方法,实例化的时候会把传递过来参数作为实例化MessageQueue的参数,并且当前的线程会获取当前的线程,表述的可能不太清晰看图吧:
isCurrentThread()方法,该方法会判断looper当前的sThread常量和Thread.currentThread()返回的变量是否相等(==)
setMessageLogging(@Nullable Printer printer)方法,会把传递过来的Printer 赋值给当前looper的mLogging变量。Printer 的用法还请再看相关介绍~
quit()方法,执行looper当前queue的quit(blooean)方法,传递false过去。
quitSafely()方法,同样执行queue的quit方法,但是会传递true过去,至于这个方法传递不同参数的含义请到queue分析当中去看。
getThread()方法,return looper当前的mThread。
getQueue()方法,return looper当前的mQueue。
dump(@NonNull Printer pw, @NonNull String prefix) 方法,会用传递过来的pw打印出prefix内容,然后执行mqueue.dump方法,该方法第三个参数为null。
dump(@NonNull Printer pw, @NonNull String prefix, Handler handler)方法,会用传递过来的pw打印出prefix内容,然后执行mqueue.dump方法,该方法第三个参数为传递过来的handler。具体执行内容也请看queue里面的dump方法。(该方法为hide,写多了)
prepareMainLooper()方法,会把false传递到要执行的prepare方法中。然后synchronized-- looper类 判断当前的looper是否为null,为null的话就走myLooper方法进行获取,不为null则会抛出IllegalStateException。
loop方法内容比较多,也需要结合代码进行查看。先进行大概描述,然后再结合图片里面的代码进行查看。
looper.loop会先执行myLooper方法获取looper判断是否为null。获取当前looper的mQueue,进入到无限循环当中,获取queue里面的message。如果message为null就return,不为null时就会获取当前的observer,获取当前message里面的相关时间和tag用来判断message的执行时间。把相关tag放到trace.tracebegin当中进行跟踪。判断当前observer是否为空不为空的话执行相应方法,首先执行messageDispatchStarting方法,在message.target执行dispatchMessage之后执行observer.messageDispatched方法,如果这个时候走到catch里面了,会执行observer的dispatchingThrewException方法。trycatch最终都会跟踪该消息。判断时间打印出相应的log,最终会执行message.recycleUnchecked()重置message 的内容和Binder.clearCallingIdentity()方法清理标识。
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
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);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
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对外暴露的方法基本都已经写出。