UiAutomator 2.0 的 StaleObjectException

StaleObjectException with UiAutomator 2.0

我正在从 uiautomator 迁移到 uiautomator 2.0。我在使用旧的 UiWatcher 时遇到了一些麻烦。

我正在使用此功能设置电池电量并检查应用程序打印的电量是否正确。这是代码。

private void setLevel(int oldL, int newL) throws UiObjectNotFoundException {
    UiWatcher okBatteryDialogWatcher = new UiWatcher() {
        @Override
        public boolean checkForCondition() {
            UiObject okCancelDialog = new UiObject(new UiSelector().textContains("Connect charger"));
            if(okCancelDialog != null){
                UiObject okButton = new UiObject(new UiSelector().className(Button.class.getName()).text("OK"));
                okButton.click();
                return device.waitForWindowUpdate("",10000);
            }
            return false;
        }
    };

    getUiDevice().registerWatcher("Battery dialog watcher", okBatteryDialogWatcher);
    getUiDevice().runWatchers();

    UiObject batteryLevel = new UiObject(new UiSelector().text(oldL + " %"));
    assertTrue("Battery level not found", batteryLevel.exists());

    BatteryDelegate.getInstance().setBatteryLevel(newL);

    batteryLevel = new UiObject(new UiSelector().text(newL + " %"));
    assertTrue("Battery level not found", batteryLevel.exists());
}

这段代码工作正常。现在我想更改它以使用uiautomator 2.0提供的新功能。

private void setLevel(int oldL, int newL) {
    UiWatcher okBatteryDialogWatcher = new UiWatcher() {
            @Override
            public boolean checkForCondition() {
                UiObject2 okCancelDialog = device.findObject(By.textContains("Connect charger"));
                if(okCancelDialog != null){
                    UiObject2 okButton = device.findObject(By.clazz(Button.class.getName()).text("OK"));
                    okButton.click();
                    return device.waitForWindowUpdate("",10000);
                }
                return false;
            }
        };

    device.registerWatcher("Battery dialog watcher", okBatteryDialogWatcher);
    device.runWatchers();

    UiObject2 batteryLevel = device.findObject(By.text(oldL + " %"));
    assertTrue("Battery level not found", batteryLevel != null);

    BatteryDelegate.getInstance().setBatteryLevel(newL);

    Boolean b = batteryLevel.wait(Until.textEquals(newL + " %"), 10000);
    assertTrue("Battery level not found", b != null && b.booleanValue());
}

当我使用此代码将电池电量设置为 5% 时(出现对话框 'Battery low'),Boolean b = batteryLevel.wait(Until.textEquals(newL + " %"), 10000);

行引发 StaleObjectException

这里是例外

android.support.test.uiautomator.StaleObjectException
at android.support.test.uiautomator.UiObject2.getAccessibilityNodeInfo(UiObject2.java:622)
at android.support.test.uiautomator.UiObject2.getText(UiObject2.java:287)
at android.support.test.uiautomator.Until.apply(Until.java:277)
at android.support.test.uiautomator.Until.apply(Until.java:274)
at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:49)
at android.support.test.uiautomator.WaitMixin.wait(WaitMixin.java:34)
at android.support.test.uiautomator.UiObject2.wait(UiObject2.java:144)
at com.mycompany.myproject.demo.sensor.BatteryTestCase.setLevel(BatteryTestCase.java:89)
at com.mycompany.myproject.demo.sensor.BatteryTestCase.testUS2(BatteryTestCase.java:44)
...

我知道异常是由于对话框引起的,但我的观察者变得无用了。我可以用像

这样的技巧来处理这个异常
....
Boolean b = null;
try {
    b = batteryLevel.wait(Until.textEquals(newL + " %"), 10000);
} catch (StaleObjectException e) {
    UiObject2 okCancelDialog = device.findObject(By.textContains("Connect charger"));
    if(okCancelDialog != null){
        UiObject2 okButton = device.findObject(By.clazz(Button.class.getName()).text("OK"));
        okButton.click();
        device.waitForWindowUpdate("",10000);
        b = batteryLevel.wait(Until.textEquals(newL + " %"), 10000);
    }
}
assertTrue("Battery level not found", b != null && b.booleanValue());
...

但这绝对不美。有人

谢谢

此问题应在 UiAutomator 2.1.0 中得到修复。观察者仅在首次调用 UiDevice.findObject(..) 时被触发,并且不会阻止 StaleObjectExceptions。

在最新版本中,如果出现 StaleObjectException,也会触发观察者。如果您获取最新的 Android 支持存储库(修订版 13)并更新您的构建文件以依赖 uiautomator-v18:2.1+,问题就会消失。