卡片不是迷你版的应用

在智能截图整理工具的开发复盘里,我们发现用户最大的诉求是“不用打开应用,扫一眼就知道今天截了什么图”。于是我们顺理成章地把应用的核心功能封装成元服务,并做了一个桌面卡片。

第一版上线,用户抱怨桌面滑动不跟手。我们查后台日志,发现每分钟卡片刷新两次,每次都把整个数据库扫一遍。要明白一个硬核概念:FormExtensionAbility 的生命周期极短,系统随时会把它干掉。你在这里面写耗时几秒的 IO 或复杂的图片解析,它不仅会触发系统超时导致卡片刷新失败,还会拖垮整个桌面进程的渲染。

轻量数据预加载与 Push 机制

卡片的刷新数据源绝不能在 onAddForm 或 onUpdateForm 里去实时查数据库。我们要把“数据计算”放在应用主进程里做,卡片只负责接收。

typescript

import { formProvider } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';

// 应用侧:处理完数据后,主动 Push 给卡片
async function pushDataToCard(formId: string, latestShots: any[]) {
  const formData = {
    "latest_title": latestShots[0].title,
    "latest_uri": latestShots[0].uri,
    "total_count": latestShots.length
  };
  
  // 构造 FormBindingData
  const bindingData = formProvider.createFormBindingData(formData);
  
  try {
    // 定向刷新特定卡片
    await formProvider.updateForm(formId, bindingData);
  } catch (error) {
    console.error(`卡片刷新失败: ${JSON.stringify(error)}`);
  }
}

updateForm 的调用必须保证数据量极小(通常不超过几十KB)。如果你把截图原图转成 Base64 塞进 formData 里,要么直接超出 IPC 通信限制报错,要么桌面直接 OOM。

常见错误是在 onUpdateForm 里发起网络请求或读数据库。超时导致 ERR_CODE_FORM_UPDATE_TIMEOUT 是常事。正确的做法是:onUpdateForm 里读一下 Preferences 里缓存好的轻量 JSON,如果没有缓存,直接返回上一次的默认数据,然后拉起主应用在后台计算,算完再用 updateForm 推过来。

卡片点击路由与参数透传

用户点击卡片上的某张截图,必须能直达详情页。元服务的拉起不能用传统的 startAbility,而是要用 postCardAction。

typescript

// 卡片 UI 侧的点击事件
Column() {
  Text('查看最近截图')
}
.onClick(() => {
  // 使用 postCardAction 触发路由
  postCardAction(this, {
    action: 'router',
    abilityName: 'EntryAbility',
    params: {
      targetPage: 'DetailPage',
      shotId: '12345'
    }
  });
})

action: 'router' 会让系统尝试以半模态或全屏方式拉起元服务。params 里的参数会通过 want.parameters 传给元服务的 onCreate 或 onNewWant。这里最容易踩的坑是参数类型:params 里只能传基本数据类型(string, number, boolean),传对象或数组会直接导致卡片点击无响应。

卡片设计的本质是“信息的极简呈现”,它承受不了复杂的业务逻辑。把重计算留在主应用,把轻量视图留给卡片,这种“瘦客户端”模式才是鸿蒙元服务的最佳实践。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐