AutoJs6 中文文档 下载 App

findOne、find、waitFor — 查找方法全解析

方法对比表

方法等待超时返回值找不到时适用场景
findOne(timeout)✅ 默认 10sUiObject 或 null返回 null最常用,等控件出现再找
findOnce()❌ 立即UiObject 或 null返回 null已知控件存在,立即查找
find()❌ 立即UiObject[]返回空数组找所有匹配控件
exists(timeout)✅ 可选boolean返回 false只关心"有没有"
waitFor(timeout)✅ 必选void超时抛异常阻塞等待控件出现
waitUntilGone(timeout)✅ 必选boolean超时返回 false等待控件消失

findOne — 最常用的方法

// 无参,默认 10 秒超时
let btn = text("登录").findOne();

// 指定 5 秒超时
let btn = text("登录").findOne(5000);

// 必须判空!找不到返回 null,不是抛异常
let btn = text("登录").findOne(2000);
if (btn) {
    btn.click();
} else {
    console.log("控件未出现");
}

findOne 的超时行为

// 内部流程:
// 0ms   → 查找一次 → 没找到 → 等 200ms
// 200ms → 查找一次 → 没找到 → 等 200ms
// ...(循环)
// 9800ms → 查找一次 → 没找到 → 退出,返回 null

findOne 在超时时间内每 200ms 重试一次,直到找到或超时。这比你自己写循环高效得多——每次查找都会刷新无障碍服务的控件树缓存。

findOnce — 立即查找

// 只查找一次,不等待
let btn = text("登录").findOnce();
if (btn) {
    btn.click();
} else {
    // 控件还没出现或不存在
}

适用场景:

// 先等出现,再一次性查找
text("登录").waitFor(5000);
let btn = text("登录").findOnce(); // 此时肯定存在
btn.click();

find — 找全部匹配

// 返回数组
let allButtons = className("Button").find();
console.log("共找到 " + allButtons.length + " 个按钮");

// 遍历
allButtons.forEach(btn => {
    console.log("按钮文字: " + (btn.text() || "(无)"));
    console.log("    位置: " + btn.bounds());
});

find 的典型用途

// 场景一:批量操作
let checkboxes = className("CheckBox").find();
checkboxes.forEach(cb => {
    if (!cb.checked()) {
        cb.click(); // 全选
    }
});

// 场景二:在列表中找某一项
let items = id("list_item").find();
let target = items.find(item => item.text().includes("目标关键词"));
if (target) {
    target.click();
}

exists — 只判断存在性

// exists 返回 boolean,不返回控件对象
if (text("确定").exists()) {
    // 存在 → 再查一次获取对象
    text("确定").findOne().click();
} else {
    // 不存在
}

// exists 也接受超时
if (text("加载中").exists(3000)) {
    // 3 秒内出现了
}

注意

exists 和 findOne 都可能要等待。如果你既需要判断存在又需要操作控件,直接用 findOne:

// ❌ 不好:两次等待
if (text("登录").exists()) {
    text("登录").findOne().click(); // 这里又等了一次
}

// ✅ 好:一次等待
let btn = text("登录").findOne(3000);
if (btn) {
    btn.click();
}

waitFor — 阻塞等待

// 阻塞直到控件出现,默认 10 秒
text("登录").waitFor();

// 自定义超时
text("登录").waitFor(5000);

// 超时未出现会抛异常!需要 catch
try {
    text("登录").waitFor(3000);
    // 到这里控件肯定存在
} catch (e) {
    console.error("控件 3 秒内未出现");
}

waitFor 不会返回控件对象,只是等待。等完需要自己再 findOnce()。

waitUntilGone — 等待消失

// 等待加载圈消失
let gone = id("loading_indicator").waitUntilGone(5000);
if (gone) {
    console.log("加载完成");
} else {
    console.log("加载超时");
}

层级内查找

所有查找方法都可以在指定控件范围内执行,而不是全屏幕:

// 先找容器
let listContainer = id("goods_list").findOne(5000);

// 在容器内找子项(只在这个容器的子树里查找)
let target = listContainer.findOne(textContains("目标商品"));

// 也可以
let allButtonsInList = listContainer.find(className("Button"));

性能与缓存

查找成本

findOnce    → 最低,只查找一次,刷新缓存
findOne     → 中等,最多 50 次查找(10s / 200ms)
find        → 中高,遍历整棵控件树

控件树刷新

每次查找都会触发无障碍服务刷新控件树缓存。以下情况会自动刷新:

// 某些情况下手动刷新
auto.refresh(); // 强制刷新控件树缓存

最佳实践

组合策略

// ✅ 推荐组合

// 1. 先等页面加载好
waitForActivity("com.example/.MainActivity", 5000);

// 2. 找关键控件操作
let btn = id("action_btn").findOne(3000);
if (btn) {
    btn.click();
} else {
    // 页面可能没加载好,处理异常
}

避免的陷阱

陷阱原因解决
findOne 后不判空返回 null 导致崩溃if (btn) 判空
find().length === 0空数组不是 null直接 .forEach(),空数组自然不执行
在 while 循环里手动 findOnce效率低直接用 findOne(timeout)
忘了 waitFor 超时抛异常脚本意外中断加 try-catch 或改用 findOne