HarmonyOS 鸿蒙Next应用升级后桌面卡片数据丢失

HarmonyOS 鸿蒙Next应用升级后桌面卡片数据丢失 卡片代码如下,已经持久化了,手机重启后数据也不会丢,但是进行版本升级后(比如1.0.0->1.0.1),卡片数据却没了

/*
 * Copyright (c) 2024 懒猫Record. All rights reserved.
 */

import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';
import { preferences } from '@kit.ArkData';
import { ItemRecordDatabase } from '../common/service/ItemRecordDatabase';
import { ItemRecord } from '../common/model/ItemRecordModel';

/**
 * 物品卡片Ability
 * 使用 DataPreferences 进行数据持久化(参考 myHistory 的存储方式)
 */
export default class ItemWidgetAbility extends FormExtensionAbility {
  /**
   * 添加卡片
   */
  onAddForm(want: Want) {
    const formId = want.parameters!['ohos.extra.param.key.form_identity'].toString();
    console.info(`ItemWidget onAddForm: formId=${formId}`);

    let options: preferences.Options = {
      name: 'itemWidgets'
    };
    preferences.removePreferencesFromCacheSync(this.context, options);
    let dataPreferences = preferences.getPreferencesSync(this.context, options);

    // 1. 更新 formIds 列表
    let preFormIdsArray: Array<string> = JSON.parse(dataPreferences.getSync('formIds', '[]').toString());
    if (preFormIdsArray && preFormIdsArray.indexOf(formId) == -1) {
      preFormIdsArray.push(formId);
    }
    dataPreferences.putSync('formIds', JSON.stringify(preFormIdsArray));

    // 2. 尝试加载该卡片的数据
    const widgetKey = `widget_${formId}`;
    let widgetDataStr = dataPreferences.getSync(widgetKey, '').toString();
    
    let widgetData: Record<string, ESObject>;
    
    if (widgetDataStr) {
      // 找到保存的数据
      widgetData = JSON.parse(widgetDataStr) as Record<string, ESObject>;
      console.info(`从 preferences 加载卡片数据: formId=${formId}`);
    } else {
      // 没有保存的数据,使用默认数据
      widgetData = {
        'formId': formId,
        'itemId': '',
        'itemName': '点击选择物品',
        'categoryName': '未设置',
        'specQuantity': 0,
        'purchaseCount': 1,
        'totalQuantity': 0,
        'remainingQuantity': 0,
        'unit': '',
        'usagePercentage': 0,
        'price': 0,
        'needSelectItem': true
      };
      
      // 保存默认数据
      dataPreferences.putSync(widgetKey, JSON.stringify(widgetData));
      console.info(`首次创建卡片,使用默认数据: formId=${formId}`);
    }

    // 3. 持久化数据
    dataPreferences.flush();

    return formBindingData.createFormBindingData(widgetData);
  }


  /**
   * 卡片更新(系统定时刷新时调用)
   * 说明:
   * 1. 系统会定时调用此方法(每30分钟一次)
   * 2. autoDeductDailyUsage() 内部已调用 refreshItemWidgets() 刷新所有相关卡片的UI
   * 3. 因此这里不需要手动调用 formProvider.updateForm()
   */
  onUpdateForm(formId: string) {
    console.info(`[卡片刷新] 系统触发定时刷新 formId=${formId}`);

    try {
      const database = ItemRecordDatabase.getInstance();
      database.initialize(this.context).then(() => {
        // 执行每日自动扣减余量(内部会自动刷新所有卡片UI)
        const updateCount = database.autoDeductDailyUsage();
        console.info(`[卡片刷新] 完成:更新了 ${updateCount} 个物品,所有关联卡片UI已同步刷新`);
      })
    } catch (error) {
      console.error('[卡片刷新] 失败:', error);
    }
  }

  /**
   * 卡片删除
   */
  onRemoveForm(formId: string) {
    console.info(`ItemWidget onRemoveForm: ${formId}`);

    let options: preferences.Options = {
      name: 'itemWidgets'
    };
    preferences.removePreferencesFromCacheSync(this.context, options);
    let dataPreferences = preferences.getPreferencesSync(this.context, options);

    // 1. 从 formIds 列表中移除
    let preFormIdsArray: Array<string> = JSON.parse(dataPreferences.getSync('formIds', '[]').toString());
    if (preFormIdsArray && preFormIdsArray.indexOf(formId) !== -1) {
      const index = preFormIdsArray.indexOf(formId);
      preFormIdsArray.splice(index, 1);
    }
    dataPreferences.putSync('formIds', JSON.stringify(preFormIdsArray));

    // 2. 删除该卡片的数据
    const widgetKey = `widget_${formId}`;
    dataPreferences.deleteSync(widgetKey);

    // 3. 持久化更改
    dataPreferences.flush();

    console.info(`卡片数据已删除: formId=${formId}`);
  }

  /**
   * 卡片事件
   */
  onFormEvent(formId: string, message: string) {
    console.info(`ItemWidget onFormEvent: formId=${formId}, message=${message}`);
  }

  /**
   * 转为普通卡片
   */
  onCastToNormalForm(formId: string) {
    console.info(`ItemWidget onCastToNormalForm: ${formId}`);
  }
}

更多关于HarmonyOS 鸿蒙Next应用升级后桌面卡片数据丢失的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

沙盒文件还在吗?

更多关于HarmonyOS 鸿蒙Next应用升级后桌面卡片数据丢失的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next应用升级后桌面卡片数据丢失,主要原因是应用升级时系统未能正确保留卡片状态数据。在鸿蒙应用模型中,桌面卡片数据与应用的持久化存储机制相互独立。应用升级过程中若未实现数据迁移逻辑,或卡片提供方未正确处理数据恢复,会导致卡片重置为默认状态。建议检查应用的卡片数据持久化方案,确保升级时通过onRestoreData等方法正确恢复数据。

在HarmonyOS Next中,应用版本升级后桌面卡片数据丢失是常见问题,主要原因是应用升级时系统会重新创建应用数据目录,导致原有的preferences数据被重置。

从你的代码分析,问题出现在每次onAddForm时都调用了removePreferencesFromCacheSync,这会清除缓存的preferences数据。虽然你使用了持久化存储,但在应用升级场景下,原有的preferences文件可能无法被正确访问。

解决方案:

  1. 移除不必要的缓存清理
// 删除这行代码
preferences.removePreferencesFromCacheSync(this.context, options);
  1. 使用应用级数据持久化: 确保preferences的name保持一致,系统会在应用升级时尝试保留这些数据。

  2. 添加数据迁移机制: 在onAddForm中增加版本检查,如果检测到新版本,尝试从旧版本迁移数据。

  3. 使用数据库备份: 考虑将关键卡片数据同时备份到应用数据库,在preferences数据丢失时能够恢复。

当前代码的主要问题是在每次添加卡片时都清除了preferences缓存,这在应用升级时会导致数据无法正确加载。建议先移除缓存清理逻辑,测试版本升级时的数据保持情况。

回到顶部