写给小白的android Handler机制详解
- 当应用启动时会默认有一个UI线程,这个线程会默认关联一个消息队列,所有的操作都会被封装为消息然后交给主线程处理。
- 在一个线程内创建Handler对象之前必须先调用Looper.prepare
- handler的无参构造函数,会调用handler两个参数的构造函数,从而调用Looper的静态方法myLooper()获取looper对象,如果looper对象为空,就会报错
- 每个Looper对象持有一个MessageQueue的引用
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;
mCallback = callback;
mAsynchronous = async;
}
- myLooper()会从sThreadLocal.get()获取Looper对象,所以在获取之前必须存入Looper对象,在源码中搜索可以发现,Looper对象在Looper.prepare函数中被存入ThreadLocal中的。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//---------------------------------------------------
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may becreatedper thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
上面的代码可以看到,prepare()先判断mLooper是否为空,如果为空的话就创建一个Looper对象,然后保存到ThreadLocal对象内。
总结:
Handler()
↓ Handler构造函数中通过Looper.myLooper()获取Looper对象
Looper.myLooper()
↓ myLooper()通过sThreadLocal.get()获取Looper对象
ThreadLocal.get()
↑ Looper.prepare()创建Looper对象保存到sThreadLocal中
Looper.prepare()
handler.sendMessager()
sendMeaasger()会调用sendMessageDelayed(),如果时间小于零就赋值为零,然后调用sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
在sendMessageAtTime()中先获取Looper对象的MessageQueue对象,然后调用 enqueueMessage()
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);
}
enqueueMessage()首先将meg.target设置为当前对象,然后调用queue.enqueueMessage()
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
queue.enqueueMessage()通过每个消息的时间将消息进行排列,用mMessage来存储当前第一个待处理的Messager,以链表的形式存储消息。现在我们已经将消息存放到消息队列了。我们知道Looper会从消息队列中取出消息然后发送给Handler处理,接下来我们看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 (;;) {
...
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
// --------------------------------------------
msg.target.dispatchMessage(msg);
// --------------------------------------------
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
}
}
直接看标记重点的代码,我们知道msg.target就是当前Handler实例,所以这里就是调用了Handler.dispatchMessage(msg)
以上就实现了Handler发送Message到MessageQueue,然后Looper.loop()调用msg.target(Handler).dispatchMessage()的过程
总结:
Handler.sendMessage()
↓ 调用sendMessageDelayed()对小于0的时间进行正规化
sendMessageDelayed()
↓ 调用sendMessageAtTime()
sendMessageAtTime()
↓ 获取Looper中的MessageQueue 然后调用enqueueMessage()
enqueueMessage()
↓ 调用queue.enqueueMessage()将消息进行入列
queue.enqueueMessage()
Handler.dispatchMessage()
↑ 通过loop()实现从消息队列中取出消息然后将调用msg.target.dispatch
Looper.loop()
Handler.post
handler.post(Runnable),在post中首先会调用getPostMessage将Runnable对象转换成Message对象
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
在post方法里面调用sendMessageDelayed()然后流程又回到了最上面
Handler.post()
↓ 在post中调用getPostMessage(Runnable r)将Runnable转换成Message,然后调用sendMessageDelayed()
sendMessageDelayed()
↓ 调用sendMessageAtTime()
sendMessageAtTime()
↓ 获取Looper中的MessageQueue 然后调用enqueueMessage()
enqueueMessage()
↓ 调用queue.enqueueMessage()将消息进行入列
queue.enqueueMessage()
Handler.dispatchMessage()
↑ 通过loop()实现从消息队列中取出消息然后将调用msg.target.dispatch
Looper.loop()
Handler.dispatchMessage
先检查Message.callback是否为空,如果不为空就执行runnable,如果为空就执行Handler.handlerMessage();
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Activity的runOnUiThread()
runOnUiThread()也可以实现在子线程内更新UI的逻辑,首先它会判断当前所在线程是否是主线程,如果不是就调用handler.post,然后流程和上面一样,如果在主线程就直接调用run()
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
上一篇: 数据湖之iceberg系列(六)-flink处理数据
下一篇: day4_字符串之键值对问题的实现
推荐阅读
-
Android Handler的使用详解
-
Android Handler的使用详解
-
Android的线程通信:消息机制原理(Message,Handler,MessageQueue,Looper),异步任务AsyncTask,使用JSON
-
详解Android Scroller与computeScroll的调用机制关系
-
Android编程中的消息机制实例详解
-
Android事件分发机制的详解
-
详解Android Scroller与computeScroll的调用机制关系
-
Android编程中的消息机制实例详解
-
详解Android中Handler的使用方法
-
详解Android中Handler的内部实现原理