本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
在鸿蒙应用开发中,ArkTS卡片是一种轻量级的服务交互形态,可以在桌面上展示应用的核心信息和功能。而卡片生命周期管理则是控制卡片从创建到销毁整个过程的机制。
创建ArkTS卡片,必须实现FormExtensionAbility生命周期接口。FormExtensionAbility是卡片提供方(应用)用于处理卡片各种状态变化的入口点。
提示:
-
FormExtensionAbility进程不能常驻后台
-
生命周期回调函数中无法处理长时间任务
-
生命周期调度完成后会继续存在10秒
-
10秒内无新回调触发则进程自动退出
二、基础配置与模块导入
2.1 导入相关模块
// entry/src/main/ets/entryformability/EntryFormAbility.ts
// FormKit模块 – 卡片相关核心功能
import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
// AbilityKit模块 – 系统能力相关
import { Configuration, Want } from '@kit.AbilityKit';
// 基础服务模块 – 错误处理
import { BusinessError } from '@kit.BasicServicesKit';
// 性能分析模块 – 日志打印
import { hilog } from '@kit.PerformanceAnalysisKit';
模块说明:
| FormKit | 卡片核心功能 | 卡片数据绑定、生命周期、更新等 |
| AbilityKit | 系统能力 | 配置信息、意图传递 |
| BasicServicesKit | 基础服务 | 错误类型定义 |
| PerformanceAnalysisKit | 性能分析 | 日志打印 |
三、FormExtensionAbility生命周期接口
3.1 生命周期方法
export default class EntryFormAbility extends FormExtensionAbility {
// 1. 添加卡片
onAddForm(want: Want): formBindingData.FormBindingData;
// 2. 更新卡片
onUpdateForm(formId: string): void;
// 3. 移除卡片
onRemoveForm(formId: string): void;
// 4. 卡片可见性变化
onChangeFormVisibility(newStatus: Record<string, number>): void;
// 5. 卡片事件
onFormEvent(formId: string, message: string): void;
// 6. 卡片状态查询
onAcquireFormState(want: Want): formInfo.FormState;
// 7. 配置更新
onConfigurationUpdate(config: Configuration): void;
// 8. 转换为普通卡片(当前无实际场景)
onCastToNormalForm(formId: string): void;
}
3.2 方法执行顺序图
卡片添加流程:
用户添加卡片 → onAddForm → 卡片显示
卡片更新流程:
定时/定点触发 → onUpdateForm → updateForm → 卡片刷新
卡片移除流程:
用户删除卡片 → onRemoveForm → 清理数据
卡片可见性变化:
划入屏幕 → onChangeFormVisibility(可见)
划出屏幕 → onChangeFormVisibility(不可见)
四、生命周期方法说明
4.1 onAddForm – 添加卡片
触发时机:卡片使用方(如桌面)创建卡片时触发
作用:卡片提供方需要返回卡片数据绑定类,用于初始化卡片显示内容
onAddForm(want: Want): formBindingData.FormBindingData {
hilog.info(0xFF00, 'EntryFormAbility', '[EntryFormAbility] onAddForm');
// 从want中获取卡片参数
const formName = want.parameters?.[formInfo.FormParam.NAME_KEY] as string;
hilog.info(0xFF00, 'EntryFormAbility', `formName: ${formName}`);
// 构建卡片数据
let obj: Record<string, string> = {
'title': 'titleOnAddForm', // 对应卡片UI中的变量
'detail': 'detailOnAddForm' // 对应卡片UI中的变量
};
// 创建卡片数据绑定对象
let formData: formBindingData.FormBindingData =
formBindingData.createFormBindingData(obj);
return formData;
}
参数说明:
| want | Want | 卡片创建时的意图信息,可通过FormParam取出卡片相关信息 |
Want中可获取的卡片参数(通过FormParam常量):
| formInfo.FormParam.NAME_KEY | 卡片名称 |
| formInfo.FormParam.DIMENSION_KEY | 卡片规格(如2×2、2×4) |
| formInfo.FormParam.TEMPORARY_KEY | 是否为临时卡片 |
返回值:formBindingData.FormBindingData – 卡片数据绑定对象
4.2 onUpdateForm – 更新卡片
触发时机:
-
卡片配置了定时刷新(updateDuration)
-
卡片配置了定点刷新(scheduledUpdateTime)
-
卡片使用方主动请求更新
作用:提供数据更新,并调用updateForm刷新卡片显示
onUpdateForm(formId: string): void {
hilog.info(0xFF00, 'EntryFormAbility', '[EntryFormAbility] onUpdateForm');
// 构建更新数据
let obj: Record<string, string> = {
'title': 'titleOnUpdateForm', // 更新标题
'detail': 'detailOnUpdateForm' // 更新详情
};
// 创建卡片数据绑定对象
let formData: formBindingData.FormBindingData =
formBindingData.createFormBindingData(obj);
// 调用updateForm刷新卡片
formProvider.updateForm(formId, formData).catch((error: BusinessError) => {
hilog.info(0xFF00, 'EntryFormAbility',
'[EntryFormAbility] updateForm, error:' + JSON.stringify(error));
});
}
参数说明:
| formId | string | 要更新的卡片实例ID |
重要方法:formProvider.updateForm(formId, formData)
-
用于通知卡片框架更新指定卡片的数据
-
返回Promise,需处理错误情况
4.3 onRemoveForm – 移除卡片
触发时机:卡片使用方删除卡片时触发
作用:清理卡片相关的持久化数据,释放资源
onRemoveForm(formId: string): void {
hilog.info(0xFF00, 'EntryFormAbility', '[EntryFormAbility] onRemoveForm');
// 删除之前持久化的卡片实例数据
// 示例:从本地数据库中删除该formId对应的数据
this.deletePersistentData(formId);
// 清理其他资源
this.releaseResources(formId);
}
private deletePersistentData(formId: string): void {
// 实际开发中实现具体的持久化数据删除逻辑
hilog.info(0xFF00, 'EntryFormAbility', `删除卡片 ${formId} 的持久化数据`);
}
private releaseResources(formId: string): void {
// 释放与卡片相关的资源
hilog.info(0xFF00, 'EntryFormAbility', `释放卡片 ${formId} 的资源`);
}
参数说明:
| formId | string | 被删除的卡片实例ID |
4.4 onChangeFormVisibility – 可见性变化
触发时机:卡片使用方发起可见或者不可见通知时触发
作用:卡片提供方根据可见性做相应处理,如暂停/恢复动画、数据更新等
限制:仅系统应用生效
onChangeFormVisibility(newStatus: Record<string, number>): void {
hilog.info(0xFF00, 'EntryFormAbility', '[EntryFormAbility] onChangeFormVisibility');
// newStatus是一个字典,key为formId,value为可见性状态
for (let [formId, status] of Object.entries(newStatus)) {
if (status === 0) {
// 卡片变为不可见
hilog.info(0xFF00, 'EntryFormAbility', `卡片 ${formId} 变为不可见`);
this.pauseAnimation(formId);
} else {
// 卡片变为可见
hilog.info(0xFF00, 'EntryFormAbility', `卡片 ${formId} 变为可见`);
this.resumeAnimation(formId);
}
}
}
private pauseAnimation(formId: string): void {
// 暂停卡片中的动画
}
private resumeAnimation(formId: string): void {
// 恢复卡片中的动画
}
参数说明:
| newStatus | Record<string, number> | 键为卡片ID,值为可见性状态(0-不可见,1-可见) |
4.5 onFormEvent – 卡片事件
触发时机:卡片支持触发事件时(如点击卡片中的按钮)
作用:处理卡片发送的事件,执行相应业务逻辑
onFormEvent(formId: string, message: string): void {
hilog.info(0xFF00, 'EntryFormAbility',
`FormAbility onFormEvent, formId = ${formId}, message: ${message}`);
// 解析事件消息
try {
const event = JSON.parse(message);
switch (event.type) {
case 'refresh':
this.handleRefreshEvent(formId, event.data);
break;
case 'navigate':
this.handleNavigateEvent(event.target);
break;
case 'action':
this.handleActionEvent(event.action, event.params);
break;
default:
hilog.warn(0xFF00, 'EntryFormAbility', `未知事件类型: ${event.type}`);
}
} catch (error) {
hilog.error(0xFF00, 'EntryFormAbility',
`事件解析失败: ${JSON.stringify(error)}`);
}
}
private handleRefreshEvent(formId: string, data: any): void {
// 处理刷新事件
// 可以更新卡片数据
const newData = formBindingData.createFormBindingData({
'title': '刷新后的标题',
'detail': '刷新后的详情'
});
formProvider.updateForm(formId, newData);
}
private handleNavigateEvent(target: string): void {
// 处理导航事件,拉起主应用
// 具体实现参考"拉起主应用"部分
}
private handleActionEvent(action: string, params: any): void {
// 处理自定义动作
hilog.info(0xFF00, 'EntryFormAbility', `执行动作: ${action}, 参数: ${JSON.stringify(params)}`);
}
参数说明:
| formId | string | 触发事件的卡片实例ID |
| message | string | 事件消息内容,通常为JSON字符串 |
4.6 onAcquireFormState – 卡片状态查询
触发时机:卡片提供方接收查询卡片状态通知时
作用:返回卡片当前状态,如是否准备好显示
onAcquireFormState(want: Want): formInfo.FormState {
hilog.info(0xFF00, 'EntryFormAbility', '[EntryFormAbility] onAcquireFormState');
// 可以根据want中的参数判断卡片状态
const formName = want.parameters?.[formInfo.FormParam.NAME_KEY] as string;
// 检查卡片是否可用
if (this.isFormAvailable(formName)) {
return formInfo.FormState.READY; // 卡片准备就绪
} else {
return formInfo.FormState.UNKNOWN; // 卡片不可用
}
}
private isFormAvailable(formName: string): boolean {
// 检查卡片是否可用
// 示例:检查配置、资源等
return true; // 默认返回true
}
返回值:formInfo.FormState枚举
| FormState.READY | 卡片已准备好,可以显示 |
| FormState.UNKNOWN | 卡片状态未知,不可用 |
4.7 onConfigurationUpdate – 配置更新
触发时机:FormExtensionAbility存活时,系统配置信息(如语言、主题)更新时触发
作用:响应系统配置变化,更新卡片内容
注意事项:FormExtensionAbility创建后10秒内无操作将会被清理
onConfigurationUpdate(config: Configuration): void {
hilog.info(0xFF00, 'EntryFormAbility',
'[EntryFormAbility] onConfigurationUpdate:' + JSON.stringify(config));
// 根据配置变化更新卡片
if (config.language) {
// 语言变化,更新多语言文本
this.updateFormTextByLanguage(config.language);
}
if (config.colorMode) {
// 主题变化,更新卡片主题
this.updateFormThemeByColorMode(config.colorMode);
}
}
private updateFormTextByLanguage(language: string): void {
// 根据新语言更新卡片文本
hilog.info(0xFF00, 'EntryFormAbility', `语言变更为: ${language}`);
// 实现具体的文本更新逻辑
}
private updateFormThemeByColorMode(colorMode: number): void {
// 根据新主题更新卡片样式
hilog.info(0xFF00, 'EntryFormAbility', `主题模式变更为: ${colorMode}`);
// 实现具体的主题更新逻辑
}
参数说明:
| config | Configuration | 系统配置信息,包含语言、颜色模式等 |
4.8 onCastToNormalForm – 转换为普通卡片
触发时机:当前卡片使用方不会涉及该场景
作用:无需实现该回调函数
onCastToNormalForm(formId: string): void {
// 当前卡片使用方不会涉及该场景,无需实现该回调函数
hilog.info(0xFF00, 'EntryFormAbility', '[EntryFormAbility] onCastToNormalForm');
// 此方法可以留空
}
五、注意事项
5.1 进程生命周期限制
// ⚠️ 重要:FormExtensionAbility进程生命周期
// 1. 生命周期回调执行完成后,进程会继续存在10秒
// 2. 10秒内无新的回调触发,进程自动退出
// 3. 无法在回调中执行长时间任务(>10秒)
// 正确示例:拉起主应用处理长时间任务
onFormEvent(formId: string, message: string): void {
if (message === 'doLongTask') {
// 拉起主应用处理
this.startMainAbility();
}
}
5.2 长时间任务处理策略
对于可能需要10秒以上才能完成的业务逻辑,建议:
拉起主应用处理
处理完成后使用updateForm通知卡片刷新
// 拉起主应用
import { common, Want } from '@kit.AbilityKit';
private async startMainAbility() {
try {
const context = this.context;
const want: Want = {
bundleName: 'com.example.myapp',
abilityName: 'EntryAbility',
parameters: {
'action': 'updateForm'
}
};
await context.startAbility(want);
} catch (error) {
hilog.error(DOMAIN_NUMBER, TAG,
`拉起主应用失败: ${JSON.stringify(error)}`);
}
}
5.3 卡片数据持久化
// 卡片数据持久化示例(使用Preferences)
import { preferences } from '@kit.ArkData';
private async saveFormData(formId: string, data: Record<string, string>) {
const prefs = await preferences.getPreferences(this.context, 'form_prefs');
await prefs.put(formId, JSON.stringify(data));
await prefs.flush();
}
private async getFormData(formId: string): Promise<Record<string, string> | null> {
const prefs = await preferences.getPreferences(this.context, 'form_prefs');
const jsonStr = await prefs.get(formId, '');
return jsonStr ? JSON.parse(jsonStr) : null;
}
private async deleteFormData(formId: string) {
const prefs = await preferences.getPreferences(this.context, 'form_prefs');
await prefs.delete(formId);
await prefs.flush();
}
六、完整生命周期实现
// entry/src/main/ets/entryformability/EntryFormAbility.ts
import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
import { Configuration, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
const TAG: string = 'EntryFormAbility';
const DOMAIN_NUMBER: number = 0xFF00;
export default class EntryFormAbility extends FormExtensionAbility {
// 1. 添加卡片
onAddForm(want: Want): formBindingData.FormBindingData {
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onAddForm');
// 获取卡片参数
const formName = want.parameters?.[formInfo.FormParam.NAME_KEY] as string;
const dimension = want.parameters?.[formInfo.FormParam.DIMENSION_KEY] as number;
hilog.info(DOMAIN_NUMBER, TAG, `formName: ${formName}, dimension: ${dimension}`);
// 根据卡片规格返回不同的初始化数据
let title = '';
let detail = '';
switch (dimension) {
case 1: // 1×2
title = '小号卡片';
detail = '这是1×2规格的卡片';
break;
case 2: // 2×2
title = '中号卡片';
detail = '这是2×2规格的卡片';
break;
case 3: // 2×4
title = '大号卡片';
detail = '这是2×4规格的卡片';
break;
default:
title = '默认卡片';
detail = '这是默认规格的卡片';
}
// 构建卡片数据
let obj: Record<string, string> = {
'title': title,
'detail': detail,
'timestamp': new Date().toLocaleString()
};
// 持久化卡片数据(可选)
this.saveFormData(want, obj);
// 创建卡片数据绑定对象
return formBindingData.createFormBindingData(obj);
}
// 2. 更新卡片
onUpdateForm(formId: string): void {
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onUpdateForm');
// 构建更新数据
let obj: Record<string, string> = {
'title': '定时更新标题',
'detail': `更新于 ${new Date().toLocaleString()}`,
'timestamp': new Date().toLocaleString()
};
// 创建卡片数据绑定对象
let formData: formBindingData.FormBindingData =
formBindingData.createFormBindingData(obj);
// 更新卡片
formProvider.updateForm(formId, formData).catch((error: BusinessError) => {
hilog.info(DOMAIN_NUMBER, TAG,
'[EntryFormAbility] updateForm, error:' + JSON.stringify(error));
});
}
// 3. 移除卡片
onRemoveForm(formId: string): void {
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onRemoveForm');
// 删除持久化的卡片数据
this.deleteFormData(formId);
}
// 4. 可见性变化
onChangeFormVisibility(newStatus: Record<string, number>): void {
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onChangeFormVisibility');
for (let [formId, status] of Object.entries(newStatus)) {
hilog.info(DOMAIN_NUMBER, TAG,
`卡片 ${formId} 可见性变更为: ${status === 1 ? '可见' : '不可见'}`);
if (status === 1) {
// 变为可见时,可以刷新数据
this.refreshFormIfNeeded(formId);
}
}
}
// 5. 卡片事件
onFormEvent(formId: string, message: string): void {
hilog.info(DOMAIN_NUMBER, TAG,
`FormAbility onFormEvent, formId = ${formId}, message: ${message}`);
try {
const event = JSON.parse(message);
if (event.action === 'refresh') {
// 手动刷新
this.handleManualRefresh(formId);
} else if (event.action === 'openApp') {
// 打开主应用
this.openMainApp();
}
} catch (error) {
hilog.error(DOMAIN_NUMBER, TAG,
`事件处理失败: ${JSON.stringify(error)}`);
}
}
// 6. 卡片状态查询
onAcquireFormState(want: Want): formInfo.FormState {
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onAcquireFormState');
return formInfo.FormState.READY;
}
// 7. 配置更新
onConfigurationUpdate(config: Configuration) {
hilog.info(DOMAIN_NUMBER, TAG,
'[EntryFormAbility] onConfigurationUpdate:' + JSON.stringify(config));
}
// 8. 转换为普通卡片(留空)
onCastToNormalForm(formId: string): void {
hilog.info(DOMAIN_NUMBER, TAG, '[EntryFormAbility] onCastToNormalForm');
}
// ============== 私有辅助方法 ==============
private saveFormData(want: Want, data: Record<string, string>): void {
// 实现卡片数据的持久化
// 可以使用Preferences、数据库等
hilog.info(DOMAIN_NUMBER, TAG, '保存卡片数据');
}
private deleteFormData(formId: string): void {
// 删除持久化的卡片数据
hilog.info(DOMAIN_NUMBER, TAG, `删除卡片 ${formId} 的数据`);
}
private refreshFormIfNeeded(formId: string): void {
// 根据需要刷新卡片
hilog.info(DOMAIN_NUMBER, TAG, `刷新卡片 ${formId}`);
}
private handleManualRefresh(formId: string): void {
// 处理手动刷新事件
const newData = formBindingData.createFormBindingData({
'title': '手动刷新',
'detail': `刷新于 ${new Date().toLocaleString()}`
});
formProvider.updateForm(formId, newData).catch((error: BusinessError) => {
hilog.error(DOMAIN_NUMBER, TAG,
`手动刷新失败: ${JSON.stringify(error)}`);
});
}
private openMainApp(): void {
// 拉起主应用
// 具体实现参考"拉起主应用"部分
hilog.info(DOMAIN_NUMBER, TAG, '拉起主应用');
}
}





