ModularObjectExtensionAbility 对象销毁了,后台任务为什么还在跑:线程模式与取消责任怎么划
模块化对象已经从页面移除,日志里网络轮询和定时任务仍在运行;再次创建对象后,两组任务同时回调。对象销毁只能结束对象自身的生命周期,不能自动猜出应用创建的异步工作应该如何取消。线程模式、任务所有者和资源释放必须在设计时写清。
验证范围:官方页面用于确认 HarmonyOS 7/API 26 的能力方向;文章代码只验证应用侧状态、预算或一致性模型。当前电脑是 API 24 SDK,且没有连接 HarmonyOS 7 真机,所以下面的断言不是 API 26 编译、设备性能或线上效果证明。
先制造一次创建销毁再创建
创建模块化对象,启动轮询和延迟任务,销毁后立即重新创建。给每次实例分配 generation,日志记录任务属于哪一代。如果第一代任务仍回调第二代页面,就说明任务没有绑定所有者。
案例一:对象内计算任务随实例取消
预处理、排序等仅服务当前对象的任务,在销毁时取消;完成回调还要核对 generation,防止取消竞态。
案例二:共享下载任务可以脱离对象继续
多个对象共同使用的资源下载不应随单个实例结束,但必须由更高层仓库持有,完成后只通知仍然订阅的实例。
对象和任务是两张生命周期表
对象析构、线程退出和 Promise/定时器取消不是同义词。应用创建的任务如果被全局队列或闭包持有,即使 UI 对象消失,工作仍然可以继续。
classTaskRegistry{privategeneration=0;privateactive=newSet<string>();start(id:string){this.active.add(id);returnthis.generation;}destroy(){this.generation++;this.active.clear();}accept(id:string,g:number){returng===this.generation&&this.active.has(id);}}constr=newTaskRegistry();constg=r.start('poll');r.destroy();if(r.accept('poll',g))thrownewError('旧任务回调越过销毁边界');这段模型用确定输入验证“对象销毁后旧一代任务不能再提交回调”。它适合先发现边界错误,但不会冒充平台接口或设备性能测试。
三种所有权设计
| 方案 | 适用范围 | 主要风险 |
|---|---|---|
| 依赖对象销毁自动停止 | 没有异步任务 | 定时器和网络任务继续运行 |
| 每个任务单独取消 | 任务较少 | 容易漏掉新任务 |
| 统一任务登记表 | 正式模块对象 | 需要明确共享任务上移 |
对象私有任务进入统一登记表并随 generation 取消;真正共享的任务上移到仓库层。不要用全局变量延长对象私有任务。
用任务登记表统一取消
封装OwnedTaskScope,提供启动、取消和代际校验。无论任务跑在哪个线程,提交到 UI 前都必须通过 scope。
跨线程回调前再做一次门禁
- 销毁后旧任务不再更新状态。
- 重复创建不会出现双重轮询。
- 共享任务的所有者不是页面对象。
- 取消竞态由 generation 门禁兜底。
- 线程模式和 Stub 工厂使用当前官方定义。
对象看不见了,不等于任务自然消失。把任务所有权写进代码结构,生命周期问题才不会变成偶发重复回调。
官方资料
- HarmonyOS 7 新能力
- 2026 年 9 月开发者月刊
- HarmonyOS 应用开发指南