本篇跟 Android UiAutomator 自動化測試相關(guān)叫确,通過閱讀以下內(nèi)容,您將了解到:UiDevice#waitForIdle 這個方法是如何通過代碼檢測到 UI 界面靜止的
通過查看調(diào)用關(guān)系膀钠,發(fā)現(xiàn) waitForIdle 的最終實現(xiàn)是在 framework 層的 UiAutomation 中
```
// UiAutomation
void waitForIdle(long idleTimeoutMillis, long globalTimeoutMillis)
```
該方法包含 2 個參數(shù)掏湾,都是超時時間,具體看看代碼邏輯推斷它們的作用
```
final long startTimeMillis = SystemClock.uptimeMillis();
if (mLastEventTimeMillis <= 0) {
? ? mLastEventTimeMillis = startTimeMillis;
}
while (true) {
? ? final long currentTimeMillis = SystemClock.uptimeMillis();
? ? final long elapsedGlobalTimeMillis = currentTimeMillis - startTimeMillis;
? ? final long remainingGlobalTimeMillis =
? ? ? ? ? ? globalTimeoutMillis - elapsedGlobalTimeMillis;
? ? if (remainingGlobalTimeMillis <= 0) {
? ? ? ? throw new TimeoutException("No idle state with idle timeout: "
? ? ? ? ? ? ? ? + idleTimeoutMillis + " within global timeout: "
? ? ? ? ? ? ? ? + globalTimeoutMillis);
? ? }
? ? final long elapsedIdleTimeMillis = currentTimeMillis - mLastEventTimeMillis;
? ? final long remainingIdleTimeMillis = idleTimeoutMillis - elapsedIdleTimeMillis;
? ? if (remainingIdleTimeMillis <= 0) {
? ? ? ? return;
? ? }
? ? try {
? ? ? ? mLock.wait(remainingIdleTimeMillis);
? ? } catch (InterruptedException ie) {
? ? ? ? /* ignore */
? ? }
}
```
這段代碼中關(guān)于時間的變量較多肿嘲,一個個看
mLastEventTimeMillis 是一個成員變量融击,它在 onAccessibilityEvent 回調(diào)中得到賦值
```
// UiAutomation$ IAccessibilityServiceClientImpl# onAccessibilityEvent
mLastEventTimeMillis = event.getEventTime();
```
記錄的是當(dāng)前收到的 AccessibilityEvent 事件時間,如果事件時間無效(mLastEventTimeMillis <= 0)雳窟,在 waitForIdle 方法中就會記錄為當(dāng)前代碼被執(zhí)行時的系統(tǒng)時間
回到 waitForIdle 方法體中尊浪,當(dāng) remainingGlobalTimeMillis <= 0 時會拋出一個異常,說的是沒有 idle 狀態(tài)封救,說明 remainingGlobalTimeMillis 是用來表示監(jiān)測 idle 超時的變量拇涤,因此 globalTimeoutMillis 是設(shè)定的監(jiān)測超時時長
當(dāng) remainingIdleTimeMillis <= 0 時,方法直接 return 了誉结,說明監(jiān)測到了 idle 狀態(tài)鹅士,因此只要該變量不大于 0,說明當(dāng)前就是界面空閑的
lapsedIdleTimeMillis 表示距離上一次收到 AccessibilityEvent 事件過去了多長時間惩坑,假如密集地收到該事件掉盅,則 currentTimeMillis - mLastEventTimeMillis 就可能始終是個負(fù)值,那么 remainingIdleTimeMillis > 0 就始終不是 idle 狀態(tài)旭贬,后續(xù)就會觸發(fā)到監(jiān)測 idle 超時
而如果某個時候不再收到該事件了怔接,那么 currentTimeMillis - mLastEventTimeMillis 足夠大,并且超過 idleTimeoutMillis (注:這個值在 UiAutomator 中寫定為 500ms)時稀轨,remainingIdleTimeMillis <= 0 就會發(fā)生
因此,wait for Idle 是否真的能夠準(zhǔn)確監(jiān)測到 idle 的關(guān)鍵是 AccessibilityEvent 事件是如何產(chǎn)生的岸军。這里主要看看該事件有哪些類型
* TYPE_VIEW_CLICKED
* TYPE_VIEW_LONG_CLICKED
* TYPE_VIEW_SELECTED
* TYPE_VIEW_FOCUSED
* TYPE_VIEW_TEXT_CHANGED
* TYPE_WINDOW_STATE_CHANGED
* TYPE_NOTIFICATION_STATE_CHANGED
* TYPE_VIEW_HOVER_ENTER
* TYPE_VIEW_HOVER_EXIT
* TYPE_TOUCH_EXPLORATION_GESTURE_START
* TYPE_TOUCH_EXPLORATION_GESTURE_END
* TYPE_WINDOW_CONTENT_CHANGED
* TYPE_VIEW_SCROLLED
* TYPE_VIEW_TEXT_SELECTION_CHANGED
* TYPE_ANNOUNCEMENT
* TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
* TYPE_GESTURE_DETECTION_START
* TYPE_GESTURE_DETECTION_END
* TYPE_TOUCH_INTERACTION_START
* TYPE_TOUCH_INTERACTION_END
* TYPE_WINDOWS_CHANGED
* TYPE_VIEW_CONTEXT_CLICKED
比如奋刽,當(dāng) view 被點(diǎn)擊,被選取艰赞,或者文字內(nèi)容發(fā)生變化等的情況下佣谐,就會發(fā)送 AccessibilityEvent 事件,也即此時不是 idle 狀態(tài)方妖。所以這個方法里體現(xiàn)的 idle狭魂,說的也正是界面的靜止?fàn)顟B(tài)