UiAutomator源碼分析之UiAutomatorBridge架構,uiautomator源碼
上一篇文章《UIAutomator源碼分析之啟動和運行》我們描述了uitautomator從命令列運行到載入測試用例運行測試的整個流程,過程中我們也描述了UiAutomatorBridge這個類的重要性,說它相當於UiAutomation的代理(我們都知道UiAutomator是通過UiAutomation和AccessibilityService進行串連然後擷取介面空間資訊和注入事件的).那麼今天開始我們就圍繞這個類以及跟它有關係的類進行進一步的分析。
1. UiAutomatorBridge架構
這一章節我們會先看UiAutomatorBridge的整體架構,往後我會編寫其他文章通過一些具體的例子把它們串起來。因為我的mackbook pro上沒有安裝類圖軟體,所以是手畫的
往下我們就去初步描述下UiAutomatorBridge跟每一個相關的類的關係。
2. UiAutomatorBridge與UiAutomation的彙總關係
UiAutomatorBridge擁有一個UiAutomation的成員變數,它們是彙總的關係,注意不是組合,因為UiAutomation不一定只能依賴UiAutomatorBridge而存在,我們上一章節的UiAutomatorTestRunner就擁有一個UiAutomation的成員變數。
一旦UiAutomator工具需要通過UiAutomatorBridge擷取介面或者注入事件的時候,就會調用該成員變數.比如下面這個很關鍵的去擷取當前介面的Root Node的方法:
/* */ public AccessibilityNodeInfo getRootInActiveWindow() {/* 66 */ return this.mUiAutomation.getRootInActiveWindow();/* */ }
3. UiAutomatorBridge與QueryController的關聯關係
QueryController做的所有事情就是去把UiSelector這個UI控制項選擇子翻譯成真實的適合我們使用的android.view.accessibility.AccessibilityNodeInfo。 UiAutomatorBridge擁有一個成員變數mQueryController儲存了QueryController的一個執行個體:
/* */ private final QueryController mQueryController;/* */
當UiObject需要擷取一個UiSelector指定的控制項資訊時,會去調用UiAutomatorBridge的getQueryController方法來獲得這個mQueryController對象來進行相應的操作,如以下的UiObject的方法findAccessibilityNodeInfo就是這樣做的:
/* */ protected AccessibilityNodeInfo findAccessibilityNodeInfo(long timeout)/* */ {/* 164 */ AccessibilityNodeInfo node = null;/* 165 */ long startMills = SystemClock.uptimeMillis();/* 166 */ long currentMills = 0L;/* 167 */ while (currentMills <= timeout) {/* 168 */ node = getQueryController().findAccessibilityNodeInfo(getSelector());/* 169 */ if (node != null) {/* */ break;/* */ }/* */ /* 173 */ UiDevice.getInstance().runWatchers();/* */ /* 175 */ currentMills = SystemClock.uptimeMillis() - startMills;/* 176 */ if (timeout > 0L) {/* 177 */ SystemClock.sleep(1000L);/* */ }/* */ }/* 180 */ return node;/* */ }
該getQueryController方法會去調用UiAutomatorBridge的getQueryController方法:
/* */ QueryController getQueryController()/* */ {/* 100 */ return UiDevice.getInstance().getAutomatorBridge().getQueryController();/* */ }從上面的類圖我們可以看到,除了UiAutomatorBridge會調用QueryController做事情外,QueryController又會反過來調用UiAutomatorBridge來做事情,因為所描述的,只有UiAutomatorBridge擁有UiAutomation的執行個體,所以QueryController會持有一個UiAutomatorBridge的執行個體:
/* */ private final UiAutomatorBridge mUiAutomatorBridge;
然後在需要的時候再調用UiAutomatorBridge,如下面的獲得Root Node的方法:
/* */ protected AccessibilityNodeInfo getRootNode()/* */ {/* 168 */ int maxRetry = 4;/* 169 */ long waitInterval = 250L;/* 170 */ AccessibilityNodeInfo rootNode = null;/* 171 */ for (int x = 0; x < 4; x++) {/* 172 */ rootNode = this.mUiAutomatorBridge.getRootInActiveWindow();/* 173 */ if (rootNode != null) {/* 174 */ return rootNode;/* */ }/* 176 */ if (x < 3) {/* 177 */ Log.e(LOG_TAG, "Got null root node from accessibility - Retrying...");/* 178 */ SystemClock.sleep(250L);/* */ }/* */ }/* 181 */ return rootNode;/* */ }
4. UiAutomatorBridge與InteractionController的關聯關係道理與以上的QueryController一樣,只是UiAutomatorBridge需要通過InteractionController做的事情不是去獲得控制項資訊,而是去注入事件。
5. UiAutomatorBridge與ShellUiAutomatorBridge的繼承關係UiAutomatorBridge是一個抽象類別,裡面的方法有以下幾個:
- getRootInActiveWindow :通過UiAutomation擷取當前視窗控制項xml資訊的根節點(通過它可以迴圈擷取所有控制項)
- injectInputEvent :通過UiAutomation注入事件
waitForIdle : 通過UiAutomation睡眠指定時間
executeCommandAndWaitForAccessibilityEvent:通過UiAutomation執行指定線程的操作然後等待預期的時間返回
takeScreenshot :通過UiAutomation進行
performGlobalAction : 通過UiAutomation去執行一些全域的動作,如開啟最近開啟過的app列表,回到home介面等
從中可以看到這些動過都是需要通過UiAutomation來執行的,但也有一些動作是不需要用UiAutomation執行的,所以我相信google是為了代碼清晰和可維護性,提供了子類ShellUiAutomatorBridge來專門處理那些不需要用到UiAutomation的情況,比如以下的isScreenOn方法就不需要用到UiAutomation,而是直接用PowerManager服務來判斷當前螢幕是否是開啟的:
/* */ public boolean isScreenOn()/* */ {/* 111 */ IPowerManager pm = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));/* */ /* 113 */ boolean ret = false;/* */ try {/* 115 */ ret = pm.isScreenOn();/* */ } catch (RemoteException e) {/* 117 */ Log.e(LOG_TAG, "Error getting screen status", e);/* 118 */ throw new RuntimeException(e);/* */ }/* 120 */ return ret;/* */ }
uiautomator 怎建一個工程
很好,辛苦樓主發這麼有意義的帖
UiAutomator測試時,點擊一個clickable屬性為false,但父控制項clickable屬性為true的控制項,操作有效?
會相當於點擊父控制項!手動點擊什麼效果應該就是什麼效果