我的應(yīng)用場景是這樣子的
我在一個異步操作中用EventBus 發(fā)送了一個事件.
在另外一個Activity 中對這個事件進行接收.
因為是異步所以我使用了View.post方法企圖讓它回到主線程更新這些數(shù)據(jù).(此時我的View 處于Detach 狀態(tài))
但是事情并沒有這么美好.
我的Runnable方法沒有觸發(fā)Run()方法.
問題出在哪里?
我排查了很久.很久,很久....
我們進入post方法:
/**
* <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);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().post(action);
return true;
}
因為我的View 處于Detach狀態(tài). 所以attachInfo 為空.所以我們進入了
ViewRootImpl.getRunQueue().post(action);
/**
* The run queue is used to enqueue pending work from Views when no Handler is
* attached. The work is executed during the next call to performTraversals on
* the thread.
* @hide
*/
static final class RunQueue {
private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
void post(Runnable action) {
postDelayed(action, 0);
}
void postDelayed(Runnable action, long delayMillis) {
HandlerAction handlerAction = new HandlerAction();
handlerAction.action = action;
handlerAction.delay = delayMillis;
synchronized (mActions) {
mActions.add(handlerAction);
}
}
void executeActions(Handler handler) {
synchronized (mActions) {
final ArrayList<HandlerAction> actions = mActions;
final int count = actions.size();
for (int i = 0; i < count; i++) {
final HandlerAction handlerAction = actions.get(i);
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
actions.clear();
}
}
正常流程是我們用post 方法加入mActions 中,在performTraversals 中調(diào)用executeActions()對這些信息進行消耗.
到這里看起來一切都是那么美好.
問題出在哪里?
static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
static RunQueue getRunQueue() {
RunQueue rq = sRunQueues.get();
if (rq != null) {
return rq;
}
rq = new RunQueue();
sRunQueues.set(rq);
return rq;
}
sRunQueues 是一個ThreadLocal 類型,也就是說你上面加入的mActions跟主線程中的mActions 不是同一個.
總結(jié):
當(dāng)你使用View 處于Detach 狀態(tài).
調(diào)用線程為非主線程.
View.post并不能把你的runnable帶到主線程執(zhí)行.
BTW:
我們可以看到RunQueue 上面有這樣的注釋.The work is executed during the next call to performTraversals on the thread. 也就是說當(dāng)你正確使用了post 方法(你的Runnable 正確加入到主線程的mActions ) 那么他也是要在下一個performTraversals方法中執(zhí)行.如果 performTraversals 不到來,你的Runnable 是不會執(zhí)行的.什么時候確保這個快速的到來呢,使用View.invalidate()