Handler简单分析-runOnUiThread,view.p
2017-04-23 本文已影响254人
姜康
网上有很多关于Handler的帖子,但是看了那么多,不自己亲自分析一下,还是虚得很
哪些地方用到了Handler?
runOnUiThread(Runnable action)
我们在Activity中写处理逻辑的时候,经常会用到这个方法,用来保证代码在UI线程中执行。
来看看它是怎么实现的:
/**
* Runs the specified action on the UI thread. If the current thread is the UI
* thread, then the action is executed immediately. If the current thread is
* not the UI thread, the action is posted to the event queue of the UI thread.
*
* @param action the action to run on the UI thread
*/
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
可以看到,如果当前线程是UI线程,则调用Handler的post方法。否则直接运行。
那么就来看看Handler的post方法:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
往下:
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
再往下:
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);
}
可以看到最后调用的方法是 sendMessageAtTime(Message msg, long uptimeMillis),该方法将消息放入MessageQueque中。
send系列其实上面这几个常用的方法最终也是调用的sendMessageAtTime(Message msg, long uptimeMillis)方法。
View中的post方法
它的作用是在UI线程中执行代码逻辑。
废话不多说,看源码:
/**
* <p>Causes the Runnable to be added to the message queue.
* The runnable will be run on the user interface thread.</p>
*
* @param action The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*
* @see #postDelayed
* @see #removeCallbacks
*/
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
View的显示都依赖于Window,而AttachInfo可以看作是View和Window的桥梁。
这里可以看到如果attachInfo不为空,则会调用Handler的post方法,否则调用getRunQueue().post(action);
这里来看一下getRunQueue().post(action)的实现
/**
* Returns the queue of runnable for this view.
*
* @return the queue of runnables for this view
*/
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}
好的,到HandlerActionQueue中看看去:
public void post(Runnable action) {
postDelayed(action, 0);
}
public void postDelayed(Runnable action, long delayMillis) {
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
synchronized (this) {
if (mActions == null) {
mActions = new HandlerAction[4];
}
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
可以看到实际上是把线程放入了 HandlerAction数组中,然后在view中会调用
executeActions方法传入handler,然后调用它的postDelayed方法。