7

我有以下脚本,用于在 Android 中使用 UiAutomator 在计算器中输入“33”。但是,只接受第一个“3”,第二次按下完全被忽略。

import com.android.uiautomator.core.*;
import com.android.uiautomator.testrunner.UiAutomatorTestCase;

public class MyFirstUiAutomatorTest extends UiAutomatorTestCase {
    UiObject getByDescription(String description) {
        return new UiObject(new UiSelector().description(description));
    }

    UiObject getByText(String description) {
        return new UiObject(new UiSelector().text(description));
    }

    UiObject scrollableGetByText(String text ) throws UiObjectNotFoundException {
            UiScrollable uiScrollable = new UiScrollable(new UiSelector().scrollable(true));
            uiScrollable.setAsHorizontalList();
            return uiScrollable.getChildByText(new UiSelector().className(
                    android.widget.TextView.class.getName()),
                    text);      
    }

    public void testStuff() throws UiObjectNotFoundException {
        getUiDevice().pressHome();
        getByDescription("Apps").clickAndWaitForNewWindow();
        getByText("Apps").click();
        scrollableGetByText("Calculator").clickAndWaitForNewWindow();

        // pressing '+' and '=' effectively clears the previous input
        getByText("+").click();
        getByText("=").click();
        getByText("3").click();
        // this second '3' is ignored
        getByText("3").click();
    }
}

我尝试在第一次单击后添加睡眠 2 秒,方法是:

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

......但这并没有改变任何东西。

我还尝试在 2 '3' 之间单击另一个按钮,即:

        new UiObject(new UiSelector().text("3")).click();
        new UiObject(new UiSelector().className("android.widget.EditText")).click();
        new UiObject(new UiSelector().text("3")).click();

...但这也不起作用。

想法?

(注意:在 AVD 中使用 Android 4.1.2;在 Ubuntu linux 12.04 上运行)

编辑,根据 Rami 的观察,我尝试了以下操作,以将相同的 UiObject 对象重用于对相同描述的第二次请求:

HashMap<String,UiObject> objectByText = new HashMap<String,UiObject>(); 
UiObject getByText(String description) {
    if( objectByText.containsKey(description)) {
        System.out.println("" + objectByText.get(description) );
        return objectByText.get(description);
    }
    System.out.println("Created new object for [" + description + "]");
    UiObject object = new UiObject(new UiSelector().text(description));
    objectByText.put(description, object );
    System.out.println("" + object );
    return object;
}

...但它没有用,即使它每次都清楚地重用相同的 UiObject,因为它只说“为 [3] 创建了新对象”一次。

然后我尝试了 UiDevice.click() 'trick',通过创建一个函数'click',再次遵循 Rami 的观察:

void click(UiObject target ) throws UiObjectNotFoundException {
    Rect rect = target.getBounds();
    System.out.println("rect: " + rect );
    getUiDevice().click(rect.centerX(), rect.centerY());
}

然而,这对我也不起作用:只出现第一个“3”,第二个被忽略,即使两次点击都明显在同一个地方,因为rect:输出位置是相同的。如果我使用自己的桌面鼠标手动单击“3”两次,则两个 3 都显示正常。

Thread.sleep()我还尝试在两次点击之间添加两秒钟,但我仍然只出现了一个“3”。

4

5 回答 5

4

尝试通过文本和类进行搜索,而不是仅按文本搜索。这是执行此操作的示例方法。

Uiobject getByTextAndClass(String text, String className) {
    return new UiObject(new UiSelector().text(text).className(className));
}

然后,如果您尝试为带有数字 3 的 Calculator 按钮调用此方法:

getByTextAndClass("3", android.widget.Button.class.getName()).click();

您可以使用 UiAutomatorViewer 工具:{android-sdk}/tools/uiautomator.bat 查看不同 UiObject 的类名和其他属性。

这适用于我的 4.2.2 设备,但我正在下载 4.1.2 以在那里进行测试。

我在 4.1.2 AVD 上尝试过,它可以在我的 Windows 机器上运行。

于 2013-07-08T18:07:05.217 回答
3

这个问题似乎内置于 UiObject 的设置方式中。据我所知, UiObject 的一个实例似乎并不指代屏幕上的特定对象。它更像是定义 UiObject 时 UiSelector 所指向的实例。这里的关键是,每次调用该对象时,它都会搜索一个符合 UiSelector 要求的新项目。

证据:

UiObject ok = new UiObject(new UiSelector().text("OK"));
ok.click();
// clicks a button with the text ok on the page
// Navigate to some different page with a button with the text ok
ok.click();
// this ok button on a completely different page is still clicked

因此,我认为 Rami 的解决方法实际上可能是通过正确的方式来实现的(通过其坐标存储对象的位置并单击该位置的中心)。关于 Rami 的解决方法需要注意的重要一点是,保存一次坐标/矩形,然后在您想要引用对象时重复使用坐标/矩形。在同一个对象上多次使用 obj.getBounds() 似乎不起作用。

此外,在 UiObject 实例化期间已经传递的项目的记录似乎存储在应用程序中。运行两次找到 UiObject(例如设置警报页面中的按钮 4)并单击它的测试与找到 UiObject 并单击两次的测试失败的方式相同。这意味着对象查询的数据必须存储在设备上,因为重置 UIautomator 没有任何区别。

于 2013-07-11T17:27:30.463 回答
2

我找到了一个小技巧来解决这个问题。每次运行测试时都获得边界,因此它不是以设备为中心的,并且会即时适应。

UiObject obj1 = new UiObject(new UiSelector().text("4"));

  Rect four = obj1.getBounds();

  getUiDevice().click(four.centerX(), four.centerY());
于 2013-07-05T22:21:44.800 回答
1

我有同样的问题,看起来它正在寻找另一个具有相同文本的 UI 元素。我正在尝试自动创建警报,但时间是例如下午 4:45。Uiautomator 会点击右边的按钮。

 clickByText("4");
 clickByText("4");
 clickByText("5");
 clickByText("PM");
 clickByText("OK");

private void clickByText(String text) throws UiObjectNotFoundException {
            UiObject obj = new UiObject(new UiSelector().text(text));
            obj.click();
    }

这是第一个“4”点击的日志:

07-04 16:54:05.259: I/QueryController(25605): 匹配选择器: UiSelector[TEXT=4] <<==>> [android.view.accessibility.AccessibilityNodeInfo@592f1; boundsInParent: 矩形(0, 0 - 202, 129); boundsInScreen: 矩形 (56, 508 - 258, 637); 包名:com.android.deskclock;类名:android.widget.Button;文字:4;内容描述:空;可检查:假;检查:假;可聚焦:真;重点:假;选择:假;可点击:真;长点击:假;启用:真;密码:假;可滚动:假;[ACTION_FOCUS、ACTION_SELECT、ACTION_CLEAR_SELECTION、ACTION_CLICK、ACTION_ACCESSIBILITY_FOCUS、ACTION_NEXT_AT_MOVEMENT_GRANULARITY、ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY]]

这是第二次“4”点击的日志:

07-04 16:54:07.798: I/QueryController(25605): 匹配选择器: UiSelector[TEXT=4] <<==>> [android.view.accessibility.AccessibilityNodeInfo@5bffd; boundsInParent: 矩形(0, 0 - 66, 90); boundsInScreen: 矩形 (191, 264 - 257, 354) ; 包名:com.android.deskclock;类名: android.widget.TextView;文字:4;内容描述:空;可检查:假;检查:假;可聚焦:错误;重点:假;选择:假;可点击:假;长点击:假;启用:真;密码:假;可滚动:假;[ACTION_SELECT、ACTION_CLEAR_SELECTION、ACTION_ACCESSIBILITY_FOCUS、ACTION_NEXT_AT_MOVEMENT_GRANULARITY、ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY]]

我们可以看到一个是点击右边的android.widget.Button,第二个是点击它寻找android.widget.TextView。

于 2013-07-05T19:36:54.163 回答
0

为 3 按钮创建一个 UiObject 并单击两次。下面是代码片段

UiObject three = new UiObject(new UiSelector().text("3"));
three.click();
three.click();
于 2014-12-11T08:52:21.317 回答