 | |  |  | 后台子线程runJsFile和runOnUiThread实时反馈
https://www.yuque.com/aiwork/nba2pr/emximr9gu1eui3tp
- // worker_file.js —— 实用型:后台批量处理 + 进度反馈
- // 被主脚本 thread.runJsFile('worker_file.js') 在【子线程】加载。
- // 设计原则:
- // 1) 子线程只负责"干活 + 喊话(reportProgress/reportDone)",自己绝不碰界面控件;
- // 2) 刷新界面一律交给主线程的 reportProgress(内部走 runOnUiThread 切回 UI 线程);
- // 3) 多线程共享同一台设备,别让两个线程同时去点屏幕抢操作。
- // ─────────────────────────────────────────────────────────────
- printl('【worker】后台任务启动');
- var TOTAL = 12; // 真实业务里换成实际任务数(如待处理订单数)
- var ok = 0, fail = 0;
- for (var i = 1; i <= TOTAL; i++) {
- // —— 这里放真实耗时逻辑:抓一条数据 / 解析一项 / 上传一个文件 / 处理一张图 ——
- java.lang.Thread.sleep(400);
- // 模拟成功/失败(真实业务按实际返回值判断,这里每第 5 项算失败,方便看反馈)
- var success = (i % 5 !== 0);
- if (success) ok++; else fail++;
- // 把"这一项的进度"反馈给主线程界面(不直接改控件,交给主线程 runOnUiThread)
- if (typeof reportProgress === 'function') {
- var status = success ? ('第 ' + i + ' 项处理成功') : ('第 ' + i + ' 项处理失败');
- reportProgress(i, TOTAL, ok, fail, status);
- }
- printl('【worker】第 ' + i + ' 项:' + (success ? '成功' : '失败'));
- }
- // 收尾:把汇总结果反馈回主线程
- if (typeof reportDone === 'function') {
- reportDone(TOTAL, ok, fail);
- }
- printl('【worker】后台任务全部跑完,子线程退出');
复制代码
- // 主脚本.js —— 被 start.js 用 Import() 执行
- // 实用型演示:后台子线程(runJsFile)批量处理任务 + 主线程(runOnUiThread)实时反馈进度到悬浮窗。
- // 设计原则:子线程只干活+喊话(reportProgress),绝不自己改界面;界面刷新一律走 runOnUiThread。
- // —— 全局 UI 引用(顶层 var = 全局,子线程回调里能访问到)——
- var gUI = null, gTv = null, gPb = null, gSub = null;
- function buildFeedbackUI() {
- gUI = new floatUI();
- gUI.loadXML(
- '<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ' +
- ' android:layout_width="match_parent" android:layout_height="wrap_content" ' +
- ' android:orientation="vertical" android:padding="12dp">' +
- ' <TextView android:id="tv" android:layout_width="match_parent" android:layout_height="wrap_content" ' +
- ' android:text="准备启动后台任务..." android:textColor="#222222" android:textSize="16sp"/>' +
- ' <TextView android:id="pb" android:layout_width="match_parent" android:layout_height="wrap_content" ' +
- ' android:text="进度:0%" android:textColor="#1565C0" android:textSize="16sp" android:layout_marginTop="6dp"/>' +
- ' <TextView android:id="sub" android:layout_width="match_parent" android:layout_height="wrap_content" ' +
- ' android:text="成功 0 / 失败 0" android:textColor="#666666" android:textSize="14sp" android:layout_marginTop="4dp"/>' +
- '</LinearLayout>'
- );
- gTv = gUI.findViewById('tv');
- gPb = gUI.findViewById('pb');
- gSub = gUI.findViewById('sub');
- }
- // 子线程调用:把"单项进度"刷到界面(必须用 runOnUiThread 切回 UI 线程改控件)
- function reportProgress(done, total, ok, fail, status) {
- var t = new thread();
- t.runOnUiThread(function () {
- if (gTv) gTv.setText(status + '(' + done + '/' + total + ')');
- if (gPb) gPb.setText('进度:' + Math.round(done * 100 / total) + '%');
- if (gSub) gSub.setText('成功 ' + ok + ' / 失败 ' + fail);
- printl('[UI] 进度刷新:' + done + '/' + total + ',' + status);
- });
- }
- // 子线程调用:全部完成后的汇总反馈
- function reportDone(total, ok, fail) {
- var t = new thread();
- t.runOnUiThread(function () {
- if (gTv) gTv.setText('✅ 全部完成:共 ' + total + ' 项');
- if (gSub) gSub.setText('成功 ' + ok + ' / 失败 ' + fail + '(失败项见日志)');
- });
- printl('主线程收到汇总:成功 ' + ok + ' / 失败 ' + fail);
- }
- function demo_runJsFile() {
- buildFeedbackUI();
- printl('界面已弹出,后台子线程开始批量处理');
- var worker = new thread();
- // 同目录相对文件名;runJsFile 自动按脚本目录解析,不要写 /sdcard/ 绝对路径
- worker.runJsFile('worker_file.js', '后台任务线程');
- // 进度由子线程回调刷新,主线程不必空轮询等它。
- // 但必须保活主线程:AIWROK 主线程一跑完,子线程和定时器全死。
- (function keepAlive() {
- if (worker.isAlive()) {
- runTime.setTimeout(keepAlive, 400);
- } else {
- printl('主线程:后台任务线程已退出');
- }
- })();
- }
- // ── 触发演示 ──
- demo_runJsFile();
复制代码
| |  | |  |
|