有好一阵子(估计有大半年)没记笔记了,工作原因,很多挺想说的,后面有机会单独记录吧。工作时间比较长,做过很多东西,但是没有系统的记录和梳理,有时候一回想或者面试(面试别人或者被别人面),发现脑子一片空白。把项目做出来可能不会有什么挑战,但是条理清晰、层次分明的剖析里面涉及的技术点,真的就只能点到为止了,很多东西知道概念或者基本能理解概念,但是想讲清楚,就困难了。后面奔着这个目标,把学习过程中我认为比较重要或者比较有意思的部分都记录一下,不管是java语言,还是安卓,还是其他技术,帮助自己理解的更深刻一些。同时也要加强动手,很多技术,只有上手摸了,才能真正理解。鉴于此,我喜欢的CTF刷题,只能优先级放低(虽然也大半年没刷了),先把JAVA和安卓系统的学一遍,其它的慢慢来。
Looper/Handler/Message是安卓上常用的消息通信机制,使用非常方便。从命名上就能看出三者的功能定位:Looper负责消息循环,Handler负责消息处理,Message是消息定义。从这个角度推理看,核心是Looper和Message,因为这个是通用方案,所以Handler更多的会做一些分发上的处理,而不会有太复杂的逻辑。
先从简单的看起,看下Handler的变量定义:
@UnsupportedAppUsage
final Looper mLooper;
final MessageQueue mQueue;
@UnsupportedAppUsage
final Callback mCallback;
final boolean mAsynchronous;
@UnsupportedAppUsage
IMessenger mMessenger;
再看下构造函数:
public Handler(@NonNull Looper looper)
public Handler(@NonNull Looper looper, @Nullable Callback callback)
public Handler(boolean async)
public Handler(@Nullable Callback callback, boolean async)
Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async)
public Handler(@Nullable 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 " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
其中,looper是必须的,即使不通过参数定义,也会通过Looper.myLooper获取到, mQueue直接取的是Looper的值,双方共用一个MessageQueue。
消息分发函数如下:
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
处理逻辑很简单:优先使用msg自带的callback进行消息处理,否则使用Handler中被设置的callback,
如果这两个callback都为null,就使用Handler定义的handleMessage方法,一般由子类覆写。
其他的大部分是快捷方法:
obtainMessage:创建新的Message实例。(Handler本身也作为参数传入)
post/postAtTime/sendMessage等等,都是发送消息,最终都会调到下面这个函数:
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
queue就是前面变量定义的mQueue,虽然目前还不清楚MessageQueue的定义,但是从这也可以推出Looper应该是通过MessageQueue进行消息循环的,机制是通过Handler的post/send等方法进行让消息入队列,Looper通过循环机制取出分发,稍后再结合源码看。
ok,到这里,前面的主要变量,除了mMessener(暂时不聊),就剩下mAsynchronous,这个值只在enqueueMessage的时候,用于设置msg的属性的。
还有少数几个不常用的函数:
public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
不知道为啥叫这个名字,其实是同步执行的一个策略,如果当前就是handler的looper线程,就直接执行,否则的话使用BlockingRunnable封装执行,BlockingRunnable是内部类,会等待直至msg被执行完毕。该方法的注释说明是不建议使用,有死锁或者其它问题,确实,不建议。
public final boolean executeOrSendMessage(@NonNull Message msg) {
if (mLooper == Looper.myLooper()) {
dispatchMessage(msg);
return true;
}
return sendMessage(msg);
}
不多说,逻辑很简单。
Message的常用字段如what、arg1、arg2这些都是用于数据传输的,看下其它变量:
@UnsupportedAppUsage
/*package*/ Handler target;
@UnsupportedAppUsage
/*package*/ Runnable callback;
// sometimes we store linked lists of these things
@UnsupportedAppUsage
/*package*/ Message next;
/** @hide */
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
target指该Message指定的处理对象,callback是指负责实际执行的方法。而next则说明使用的是链表结构,静态变量sPool则说明整个进程共享一个Message链表。
//Return a new Message instance from the global pool. Allows us to
//avoid allocating new objects in many cases.
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
obtain是获取Message的静态方法,逻辑很简单,优先从链表取, 如果没有链表,则返回一个新对象。可以看出sPool是废弃Message的表头,如果表头不为空,则直接返回表头,并将新表头设为原表头的next,同时将原表头的next置空。sPoolSize用于计算链表大小,用于控制内存占用。
既然使用废弃Message链表,那就有生成的地方,那就是recycleUnchecked函数:
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
@UnsupportedAppUsage
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
recycleUnchecked前面一堆都是数据清理,后面几行就是将本Message设为新表头,并将next设为原表头,更新计数。从obtain和recycle函数来看,使用链表来缓存废弃Message真是方便实用。
其他函数都是些简单的静态方法,略过不表。不过源码看到这里,相信有的同学一定有跟我一样的疑问,既然Message有next,那MessageQueue是个什么形态?先看Looper,结合Looper食用更佳。
从前面的分析可以看出Looper主要用于消息循环。
// sThreadLocal.get() will return null unless you've called prepare().
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
@UnsupportedAppUsage
private static Looper sMainLooper; // guarded by Looper.class
private static Observer sObserver;
@UnsupportedAppUsage
final MessageQueue mQueue;
final Thread mThread;
private boolean mInLoop;
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
基本上,讲解Looper使用的书籍,都要强调使用Looper必须先调用prepare,确实,从上面两个函数可以看出,Looper是跟线程绑定的,一个线程有且只有一个Looper,通过ThreadLocal变量来控制。其他变量:sObserver从名称基本就可以确定是观察者,观察消息分发相关的事情;sMainLooper,静态变量,对应进程的主线程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.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
// 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);
me.mSlowDeliveryDetected = false;
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
loop函数,前面是一些状态判断,关键的循环在后面几行,通过loopOnce进行消息获取和分发。
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
1)Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
// 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 {
2)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 (me.mSlowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
me.mSlowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
me.mSlowDeliveryDetected = 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);
}
3)msg.recycleUnchecked();
return true;
}
这个函数看似很长,中间大段代码都是辅助功能,关键流程就是标注数字的3行
1)Message msg = me.mQueue.next();
用来取消息
2)msg.target.dispatchMessage(msg);
用来进行消息分发处理,由对应的Handler的dispathMessage方法出来该消息
3)msg.recycleUnchecked();
消息处理完毕后,进行回收处理。
从这个处理链条来看,Looper就是个引擎,用for循环来当发动机进行消息驱动,是个典型的消息获取、分发逻辑,而链条则是MessageQueue,Handler中使用enqueueMessage进行消息入队,Looper使用next获取消息出队,下面我们就从这两个方法入手来分析。
oops,文章超长,另开一篇继续。