元服务卡片定时刷新不执行?FormExtensionAbility 定时更新完整排查与实战
·
元服务卡片定时刷新不执行?FormExtensionAbility 定时更新完整排查与实战
前言
元服务(原原子化服务)的桌面卡片是用户获取信息的第一入口,很多开发者反馈「FormExtensionAbility 配置了定时刷新,但卡片内容半天不更新」。这个现象背后并不是某一个 API 失效,而是 HarmonyOS 的卡片刷新机制由刷新方式、卡片可见性、应用冻结状态、最小刷新周期四重约束共同决定。本文结合实际踩坑,给出一套可落地的排查清单与可运行代码。
问题描述
典型现象:
- 在
FormExtensionAbility.onUpdateForm里写了刷新逻辑,但卡片加到桌面后只在首次添加时执行一次,之后不再触发; - 调用
formProvider.setFormNextRefreshTime后,约定的时间点到了内容却没变; - 真机静置几小时后,卡片时间/数据明显过期;
- 后台被系统回收后,卡片彻底停在最后一次快照。
开发者容易误以为「设置了 updateDuration 就会准点刷新」,但系统对卡片刷新有严格的节流与可见性门控。
细节解析
HarmonyOS 卡片刷新有三类入口,行为各不相同:
- 定时刷新(
updateDuration):module.json5中formConfig的updateDuration以 30 分钟为最小粒度("1"= 30min,"2"= 1h……)。注意它不是「每 N 分钟」的精确定时器,系统会在接近该周期时合并触发,且受后台管控影响。 - 下次刷新时刻(
setFormNextRefreshTime):主动指定某时刻刷新,最小间隔同样受系统约束(默认不低于 5 分钟,过低会被忽略)。必须在onAddForm/onUpdateForm之后调用才生效。 - 主动推送(
formProvider.updateForm):由你的业务在任意时刻推数据,最可靠,但要求应用进程存活(或被formProvider拉起)。
最容易踩的三个坑:
- 卡片不可见时不刷新:系统仅在卡片处于桌面可见区域时触发定时刷新;被移到其他屏、藏在文件夹深层、或被设为「不通知」的卡片,定时刷新会被暂停。
- 应用被冻结/回收:非长驻后台的元服务在静置后进程冻结,定时刷新依赖系统拉起
FormExtensionAbility,若extensionAbility配置错误或onUpdateForm抛异常,刷新静默失败。 updateDuration与setFormNextRefreshTime互斥:设置了updateDuration后,再调用的setFormNextRefreshTime会被系统忽略,二者只能取其一作为「周期性」来源。
示例代码
entry/src/main/ets/entryformability/EntryFormAbility.ts:
import { formBindingData, formProvider, FormExtensionAbility } from '@kit.FormKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
const DOMAIN = 0xfeed;
export default class EntryFormAbility extends FormExtensionAbility {
// 首次添加卡片:立即给一帧数据,并规划下一次刷新
onAddForm(want: Want): formBindingData.FormBindingData {
const data = this.buildBindingData();
this.scheduleNext(Number(want.parameters?.formId));
return formBindingData.createFormBindingData(data);
}
// 系统到达刷新点会回调这里——不要在这里做网络请求后“直接 return”,
// 必须调用 updateForm 把新数据推回卡片
onUpdateForm(formId: string): void {
const data = this.buildBindingData();
formProvider.updateForm(formId, formBindingData.createFormBindingData(data))
.then(() => this.scheduleNext(Number(formId)))
.catch((err: BusinessError) => {
hilog.error(DOMAIN, 'Form', `updateForm failed: ${err.code} ${err.message}`);
});
}
// 主动规划下一次刷新(最小间隔 5 分钟,低于此值系统忽略)
private scheduleNext(formId: number): void {
const next = Date.now() + 30 * 60 * 1000; // 30 分钟后
formProvider.setFormNextRefreshTime(formId, next)
.then(() => hilog.info(DOMAIN, 'Form', `next refresh @ ${next}`))
.catch((err: BusinessError) => {
hilog.error(DOMAIN, 'Form', `setNextRefreshTime err: ${err.code}`);
});
}
private buildBindingData(): Record<string, Object> {
return {
title: '实时天气',
temperature: `${20 + Math.floor(Math.random() * 8)}℃`,
updatedAt: new Date().toLocaleTimeString(),
};
}
}
module.json5 中卡片配置(二选一,不要同时写 updateDuration 又调 setFormNextRefreshTime):
"forms": [
{
"name": "widget",
"src": "./ets/widget/pages/WidgetCard.ets",
"uiSyntax": "arkts",
"window": { "designWidth": 720, "autoDesignWidth": true },
"colorMode": "auto",
"isDynamic": true,
"updateDuration": 1,
"defaultDimension": "2*2",
"supportDimensions": ["2*2", "2*4"]
}
]
WidgetCard.ets 卡片页面用 LocalStorage 接收数据:
let storage = new LocalStorage();
@Entry(storage)
@Component
struct WidgetCard {
@LocalStorageProp('temperature') temperature: string = '--';
@LocalStorageProp('updatedAt') updatedAt: string = '';
build() {
Column() {
Text(this.temperature).fontSize(24).fontWeight(FontWeight.Bold)
Text(`更新于 ${this.updatedAt}`).fontSize(12).fontColor('#999')
}.padding(12)
}
}
关键修正:如果你需要「准点且可控」的刷新,请删掉 updateDuration,改用 setFormNextRefreshTime + onUpdateForm 自调度,并在 onUpdateForm 里始终 updateForm 回推;若数据来自网络,把网络请求放到 onUpdateForm 内并用 updateForm 回填,避免依赖已被冻结的常驻进程。
总结
- 定时刷新 ≠ 精确定时器:
updateDuration最小 30 分钟且会被系统合并/节流,且仅卡片可见时触发; updateDuration与setFormNextRefreshTime互斥,选其一;- 可靠刷新靠「
onUpdateForm内调用formProvider.updateForm自调度 + 网络数据回填」; - 排查顺序:卡片是否在桌面可见 → 进程是否被冻结 →
onUpdateForm是否抛异常 → 是否同时配了两种刷新方式冲突。
更多推荐



所有评论(0)