本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、卡片刷新的三种方式

卡片刷新中的角色:

  • 卡片提供方:提供卡片内容的应用(比如:天气应用)

  • 卡片使用方:展示卡片的系统组件(比如:桌面)

  • 卡片管理服务:系统服务,负责调度刷新

卡片刷新的三种方式:

刷新方式 触发方 适用场景
提供方主动刷新 应用自己 数据变化时实时更新
使用方主动刷新 桌面等 系统语言/主题变化
定时定点刷新 系统服务 周期性更新

备注:无论哪种刷新方式,最终都需要卡片提供方推送数据

二、数据交互

卡片和应用之间通信:

核心接口

  • updateForm:提供方→卡片,推送数据

  • postCardAction:卡片→提供方,发送事件

限制

// 错误:不能这样
let context = getContext(this); // 不能使用!

// 正确:必须用LocalStorageProp
@Entry
@Component
struct WidgetCard {
    @LocalStorageProp('title') title: string = '';
    // ...
}

为什么? 因为卡片和应用是两个独立进程,不能直接拿上下文,只能用LocalStorageProp传数据。而且数据传到卡片后,会自动变成string类型

三、主动刷新

1. 卡片提供方主动刷新(最常用)

当应用数据变化时(比如天气变了),主动告诉卡片更新:

// EntryFormAbility.ts
import { formBindingData, formProvider } from '@kit.FormKit';

export default class EntryFormAbility extends FormExtensionAbility {
    
    // 主动刷新方法
    refreshCard(formId: string) {
        // 准备新数据
        let obj = {
            'title': '最新天气',
            'detail': '晴 25°C',
            'updateTime': new Date().toLocaleString()
        };
        
        // 创建数据绑定对象
        let formData = formBindingData.createFormBindingData(obj);
        
        // 调用updateForm刷新卡片
        formProvider.updateForm(formId, formData)
            .then(() => console.log('刷新成功'))
            .catch(err => console.error('刷新失败', err));
    }
    
    // 天气变化时调用
    onWeatherChange(formId: string) {
        this.refreshCard(formId);
    }
}

2. 卡片使用方主动刷新(仅系统应用)

当系统语言、深浅色变化时,桌面可以主动请求刷新:

// 注意:仅系统应用可用!
import { formHost } from '@kit.FormKit';

function requestFormRefresh(formId: string) {
    formHost.requestForm(formId)
        .then(() => console.log('请求刷新成功'))
        .catch(err => console.error('请求失败', err));
}

普通应用这个接口用不了,了解即可。

四、被动刷新(定时定点)

不需要代码触发,只要配置好,系统自动刷新!

配置文件 form_config.json

{
  "forms": [
    {
      "name": "weather_widget",
      "src": "./ets/widget/pages/WeatherWidget.ets",
      "uiSyntax": "arkts",
      
      // 开启刷新
      "updateEnabled": true,
      
      // 定时刷新:每30分钟一次(30×1分钟)
      "updateDuration": 1,
      
      // 定点刷新:每天10:30刷新
      "scheduledUpdateTime": "10:30"
    }
  ]
}

优先级规则

重要updateDuration优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration为准!

被动刷新的代码实现

// EntryFormAbility.ts
export default class EntryFormAbility extends FormExtensionAbility {
    
    // 系统自动调用这个方法
    onUpdateForm(formId: string): void {
        console.log('被动刷新触发');
        
        // 获取最新数据
        let formData = formBindingData.createFormBindingData({
            'title': '定时更新',
            'detail': `刷新于 ${new Date().toLocaleString()}`
        });
        
        // 更新卡片
        formProvider.updateForm(formId, formData);
    }
}

五、完整示例

卡片UI(WidgetCard.ets)

@Entry
@Component
struct WidgetCard {
    @LocalStorageProp('city') city: string = '北京';
    @LocalStorageProp('weather') weather: string = '晴';
    @LocalStorageProp('temp') temp: string = '25°C';
    @LocalStorageProp('updateTime') updateTime: string = '';

    build() {
        Column() {
            Text(this.city).fontSize(14).fontColor('#666')
            Text(this.weather).fontSize(20).fontWeight(FontWeight.Bold)
            Text(this.temp).fontSize(16)
            Text(`更新: ${this.updateTime}`).fontSize(10).fontColor('#999')
            
            Button('刷新')
                .fontSize(12)
                .onClick(() => {
                    // 点击按钮通知应用更新数据
                    postCardAction(this, {
                        action: 'message',
                        content: 'user_refresh'
                    });
                })
        }
        .padding(12)
        .width('100%')
        .height('100%')
    }
}

卡片提供方(EntryFormAbility.ets)

export default class EntryFormAbility extends FormExtensionAbility {
    
    // 添加卡片时的初始化数据
    onAddForm(want: Want): formBindingData.FormBindingData {
        return this.buildFormData('初始化数据');
    }
    
    // 定时刷新触发
    onUpdateForm(formId: string): void {
        this.updateCard(formId, '定时刷新');
    }
    
    // 点击按钮触发
    onFormEvent(formId: string, message: string): void {
        if (message === 'user_refresh') {
            this.updateCard(formId, '手动刷新');
        }
    }
    
    // 统一的更新方法
    private updateCard(formId: string, type: string) {
        let formData = this.buildFormData(type);
        formProvider.updateForm(formId, formData)
            .catch(err => console.error('更新失败', err));
    }
    
    private buildFormData(type: string): formBindingData.FormBindingData {
        // 这里可以从网络获取真实天气数据
        return formBindingData.createFormBindingData({
            'city': '北京',
            'weather': '晴',
            'temp': '25°C',
            'updateTime': `${type} ${new Date().toLocaleTimeString()}`
        });
    }
}

六、踩坑

1. 权限限制

// 不要试图刷新别人的卡片
formProvider.updateForm('别人的卡片ID', data); // 无效!

// 只能刷新自己的卡片
formProvider.updateForm('自己的卡片ID', data); // 正确

2. 数据大小限制(API版本不同)

API版本 数据限制 图片限制
API 20+ 总数据 ≤ 10MB 图片 ≤ 20张
**API 19- ** - 图片 ≤ 5张,每张 ≤ 2MB

警告:超出限制的图片会显示异常,别问我怎么知道的...

常见问题汇总

问题 可能原因 解决方案
卡片不刷新 忘记调updateForm 检查onUpdateForm里有没有调用
图片显示不出来 超出大小限制 压缩图片或减少图片
刷新时间不对 优先级搞错了 检查updateDuration和scheduledUpdateTime
数据没更新 LocalStorageProp用错了 检查key是否一致
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐