事件循环与异步处理 — AutoJs6 中的并发模型
Rhino 不是浏览器
Rhino 没有浏览器那样的完整事件循环系统(Event Loop),也不提供 async/await。AutoJs6 在此基础上通过以下机制提供异步能力:
setTimeout 与 setInterval
AutoJs6 提供了全局版本的定时器函数:
// 延迟 1 秒执行
setTimeout(() => {
toast("延迟执行");
}, 1000);
// 每 2 秒执行一次(无限循环)
let timer = setInterval(() => {
console.log("定期执行: " + new Date().toLocaleTimeString());
}, 2000);
// 停止定时器
clearInterval(timer);
注意事项
setTimeout/setInterval不是浏览器原生实现,由 AutoJs6 引擎层提供- 同一引擎实例内的定时器会被排队执行
- 脚本退出时定时器自动清除
engines 模块:多引擎并发
当你需要真正的并发执行时,engines 模块是正确选择——它可以启动新的脚本引擎实例,实现脚本间并行运行。
启动新引擎
// 启动一个新引擎执行脚本(异步)
let engine = engines.execScript(
"后台任务", // 引擎名称
`
console.log("我在后台运行");
sleep(3000);
console.log("后台任务完成");
`,
{ // 可选配置
delay: 1000, // 延迟启动
loopTimes: 3, // 循环次数
interval: 5000 // 循环间隔
}
);
// engine 对象可以用来控制
console.log("引擎 ID: " + engine.id);
// engine.stop() → 停止
// engine.kill() → 强制终止
// engine.waitFor() → 等待结束
引擎间通信
// 主引擎定义全局变量,子引擎可以访问
globalThis.sharedData = { counter: 0 };
let engine = engines.execScript("子引擎", `
// 读取共享数据
let data = globalThis.sharedData;
data.counter++;
console.log("计数器: " + data.counter);
`);
多引擎协作示例
// 主脚本:并行执行多个自动化任务
// 任务 A:自动签到
let taskA = engines.execScript("签到", `
app.launchApp("签到应用");
// ... 签到逻辑
`);
// 任务 B:自动清理
let taskB = engines.execScript("清理", `
// ... 清理缓存逻辑
`);
// 等待两个任务都完成
engines.waitForAny([taskA, taskB]);
toast("至少一个任务完成了");
// 或等待全部完成
engines.waitForAll([taskA, taskB]);
toast("全部完成");
events 模块:系统事件监听
events 模块可以监听 Android 系统和应用的事件:
// 监听屏幕解锁
events.on("screen_unlocked", () => {
console.log("屏幕已解锁");
});
// 监听按键事件
events.on("key", (keyCode, event) => {
if (event.getAction() === event.ACTION_UP) {
console.log("按键释放: " + keyCode);
}
});
// 监听应用启动
events.on("app_launch", (pkg, activity) => {
console.log("应用启动: " + pkg + "/" + activity);
});
事件类型清单
| 事件名 | 触发时机 | 回调参数 |
|---|---|---|
accessibility | 无障碍服务事件 | AccessibilityEvent |
key | 物理按键事件 | keyCode, event |
broadcast | 系统广播 | context, intent |
app_launch | 应用启动 | pkg, activity |
app_remove | 应用卸载 | pkg |
notification | 通知收到 | Notification, pkg |
screen_on/off/lock/unlock | 屏幕状态 | - |
battery_changed | 电量变化 | - |
Promise 与回调
Rhino 对 Promise 的支持有限,推荐使用回调风格:
// 回调式
function asyncTask(callback) {
setTimeout(() => {
callback(null, "任务完成");
}, 1000);
}
asyncTask((err, result) => {
if (err) {
console.error("错误: " + err);
} else {
console.log("结果: " + result);
}
});
常见陷阱
sleep 阻塞整个引擎
// ❌ 错误:会阻塞整个脚本引擎
sleep(5000);
// 这 5 秒内整个脚本都无法响应任何事件
// ✅ 正确:用 setTimeout 或分引擎
setTimeout(() => {
// 这里的代码在延迟后执行,不会阻塞其他逻辑
}, 5000);
多引擎间不要共享 UI 操作
UI 操作(控件点击、滑动)应该在同一个引擎中完成。跨引擎并发做 UI 操作可能导致无障碍服务冲突。
定时器不会自动清理
如果脚本中有循环定时器但没有 clearInterval,即使脚本逻辑执行完了定时器仍会继续触发,直到引擎被销毁(应用退出或 engines.killAll())。