HarmonyOS_ArkTs_API(3)

概述

数据持久化系统是此应用的基础架构组件,负责管理用户数据的存储、检索和同步。该系统基于鸿蒙HarmonyOS ArkTS构建,采用多层数据存储策略,确保用户梦想、任务和进度等关键信息可靠存储并随时可访问。系统集成了本地数据持久化与云端同步功能,在提供离线使用能力的同时,也保障了跨设备数据一致性。

技术架构

存储层级

数据持久化系统采用分层架构,包括以下几个核心层级:

  1. 内存缓存层:提供高速数据访问,减少IO操作
  2. 本地存储层:包含轻量级偏好设置和结构化数据存储
  3. 云端同步层:实现数据备份和多设备同步

核心技术选型

系统使用多种鸿蒙原生技术实现数据持久化:

// 相关技术导入
import dataPreferences from '@ohos.data.preferences';
import relationalStore from '@ohos.data.relationalStore';
import distributedKVStore from '@ohos.data.distributedKVStore';
import fileio from '@ohos.fileio';

本地数据存储实现

首选项存储

用于存储轻量级配置信息和用户偏好:

export class PreferenceManager {
  private static instance: PreferenceManager;
  private preferences: dataPreferences.Preferences = null;
  private static PREFERENCE_NAME = 'dream_planner_prefs';
  
  private constructor() {}
  
  static getInstance(): PreferenceManager {
    if (!PreferenceManager.instance) {
      PreferenceManager.instance = new PreferenceManager();
    }
    return PreferenceManager.instance;
  }
  
  async init(context: Context): Promise<void> {
    try {
      this.preferences = await dataPreferences.getPreferences(context, PreferenceManager.PREFERENCE_NAME);
      console.info('偏好设置初始化成功');
    } catch (error) {
      console.error(`偏好设置初始化失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async putString(key: string, value: string): Promise<void> {
    try {
      await this.preferences.put(key, value);
      await this.preferences.flush();
    } catch (error) {
      console.error(`存储字符串失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async getString(key: string, defaultValue: string = ''): Promise<string> {
    try {
      return await this.preferences.get(key, defaultValue) as string;
    } catch (error) {
      console.error(`获取字符串失败: ${error instanceof Error ? error.message : String(error)}`);
      return defaultValue;
    }
  }
  
  async putNumber(key: string, value: number): Promise<void> {
    try {
      await this.preferences.put(key, value);
      await this.preferences.flush();
    } catch (error) {
      console.error(`存储数值失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async getNumber(key: string, defaultValue: number = 0): Promise<number> {
    try {
      return await this.preferences.get(key, defaultValue) as number;
    } catch (error) {
      console.error(`获取数值失败: ${error instanceof Error ? error.message : String(error)}`);
      return defaultValue;
    }
  }
  
  async putBoolean(key: string, value: boolean): Promise<void> {
    try {
      await this.preferences.put(key, value);
      await this.preferences.flush();
    } catch (error) {
      console.error(`存储布尔值失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {
    try {
      return await this.preferences.get(key, defaultValue) as boolean;
    } catch (error) {
      console.error(`获取布尔值失败: ${error instanceof Error ? error.message : String(error)}`);
      return defaultValue;
    }
  }
  
  async removeKey(key: string): Promise<void> {
    try {
      await this.preferences.delete(key);
      await this.preferences.flush();
    } catch (error) {
      console.error(`删除键值失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async clearAll(): Promise<void> {
    try {
      await this.preferences.clear();
      await this.preferences.flush();
    } catch (error) {
      console.error(`清除所有偏好设置失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
}

// 使用示例
export async function saveUserToken(token: string): Promise<void> {
  const prefManager = PreferenceManager.getInstance();
  await prefManager.putString('user_token', token);
}

export async function getUserToken(): Promise<string> {
  const prefManager = PreferenceManager.getInstance();
  return await prefManager.getString('user_token', '');
}

关系型数据存储

用于存储结构化数据,如梦想和任务信息:

export class DatabaseManager {
  private static instance: DatabaseManager;
  private store: relationalStore.RdbStore = null;
  private static DB_NAME = 'dream_planner.db';
  private static DB_VERSION = 1;
  
  // 数据库配置
  private static getConfig(): relationalStore.StoreConfig {
    return {
      name: DatabaseManager.DB_NAME,
      securityLevel: relationalStore.SecurityLevel.S1,
      encrypt: false,
      version: DatabaseManager.DB_VERSION
    };
  }
  
  private constructor() {}
  
  static getInstance(): DatabaseManager {
    if (!DatabaseManager.instance) {
      DatabaseManager.instance = new DatabaseManager();
    }
    return DatabaseManager.instance;
  }
  
  async init(context: Context): Promise<void> {
    try {
      this.store = await relationalStore.getRdbStore(context, DatabaseManager.getConfig());
      await this.createTables();
      console.info('数据库初始化成功');
    } catch (error) {
      console.error(`数据库初始化失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  private async createTables(): Promise<void> {
    try {
      // 创建梦想表
      await this.store.executeSql(
        `CREATE TABLE IF NOT EXISTS dreams (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          user_id INTEGER NOT NULL,
          title TEXT NOT NULL,
          description TEXT,
          category INTEGER,
          target_date TEXT,
          progress INTEGER DEFAULT 0,
          priority INTEGER DEFAULT 0,
          status INTEGER DEFAULT 0,
          cover_image TEXT,
          created_at TEXT,
          updated_at TEXT
        );`
      );
      
      // 创建任务表
      await this.store.executeSql(
        `CREATE TABLE IF NOT EXISTS tasks (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          dream_id INTEGER NOT NULL,
          title TEXT NOT NULL,
          description TEXT,
          status INTEGER DEFAULT 0,
          priority INTEGER DEFAULT 0,
          deadline TEXT,
          completion_date TEXT,
          notes TEXT,
          created_at TEXT,
          updated_at TEXT,
          FOREIGN KEY (dream_id) REFERENCES dreams (id) ON DELETE CASCADE
        );`
      );
      
      // 创建进度记录表
      await this.store.executeSql(
        `CREATE TABLE IF NOT EXISTS progress_logs (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          dream_id INTEGER NOT NULL,
          task_id INTEGER,
          progress_value INTEGER NOT NULL,
          notes TEXT,
          created_at TEXT,
          FOREIGN KEY (dream_id) REFERENCES dreams (id) ON DELETE CASCADE,
          FOREIGN KEY (task_id) REFERENCES tasks (id) ON DELETE SET NULL
        );`
      );
      
      console.info('数据库表创建成功');
    } catch (error) {
      console.error(`创建数据库表失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async insert(table: string, values: relationalStore.ValuesBucket): Promise<number> {
    try {
      return await this.store.insert(table, values);
    } catch (error) {
      console.error(`插入数据失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async update(table: string, values: relationalStore.ValuesBucket, predicates: relationalStore.RdbPredicates): Promise<number> {
    try {
      return await this.store.update(values, predicates);
    } catch (error) {
      console.error(`更新数据失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async delete(predicates: relationalStore.RdbPredicates): Promise<number> {
    try {
      return await this.store.delete(predicates);
    } catch (error) {
      console.error(`删除数据失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
  
  async query(predicates: relationalStore.RdbPredicates): Promise<relationalStore.ResultSet> {
    try {
      return await this.store.query(predicates, null);
    } catch (error) {
      console.error(`查询数据失败: ${error instanceof Error ? error.message : String(error)}`);
      throw error;
    }
  }
}

// 使用示例
export async function saveDreamLocally(dream: Dream): Promise<number> {
  const dbManager = DatabaseManager.getInstance();
  const values: relationalStore.ValuesBucket = {
    user_id: dream.userId,
    title: dream.title,
    description: dream.description,
    category: dream.category,
    target_date: dream.targetDate,
    priority: dream.priority,
    status: dream.status,
    progress: dream.progress,
    cover_image: dream.coverImage,
    created_at: getCurrentDateTime(),
    updated_at: getCurrentDateTime()
  };
  
  return await dbManager.insert('dreams', values);
}

数据同步机制

云端同步策略

系统实现了智能同步策略,优化数据流量和电池使用:

export class DataSyncManager {
  private static instance: DataSyncManager;
  private syncTimer: number = -1;
  private isSyncing: boolean = false;
  private pendingChanges: Map<string, any[]> = new Map(); // 待同步的变更
  private networkObserver: NetStatusListener = null;
  
  private constructor() {
    this.initNetworkObserver();
  }
  
  static getInstance(): DataSyncManager {
    if (!DataSyncManager.instance) {
      DataSyncManager.instance = new DataSyncManager();
    }
    return DataSyncManager.instance;
  }
  
  private initNetworkObserver(): void {
    // 监听网络状态变化,适应同步策略
    this.networkObserver = {
      onNetStatusChange: (status: number) => {
        if (status === 1) { // 网络可用
          if (this.pendingChanges.size > 0) {
            this.syncData(); // 网络恢复时立即尝试同步
          }
        }
      }
    };
    // 注册网络观察者
    network.subscribe(this.networkObserver);
  }
  
  // 开始定期同步
  startPeriodicSync(intervalMinutes: number = 15): void {
    if (this.syncTimer !== -1) {
      return; // 已经在同步中
    }
    
    const intervalMs = intervalMinutes * 60 * 1000;
    this.syncTimer = setInterval(() => {
      this.syncData();
    }, intervalMs);
    
    console.info(`数据同步计划已启动,间隔${intervalMinutes}分钟`);
  }
  
  // 停止定期同步
  stopPeriodicSync(): void {
    if (this.syncTimer !== -1) {
      clearInterval(this.syncTimer);
      this.syncTimer = -1;
      console.info('数据同步计划已停止');
    }
  }
  
  // 添加待同步的变更
  addChangeToSync(entityType: string, data: any): void {
    if (!this.pendingChanges.has(entityType)) {
      this.pendingChanges.set(entityType, []);
    }
    
    this.pendingChanges.get(entityType).push(data);
    console.info(`已添加变更到同步队列: ${entityType}`);
  }
  
  // 执行数据同步
  async syncData(): Promise<boolean> {
    if (this.isSyncing) {
      console.info('同步操作正在进行中,跳过本次同步');
      return false;
    }
    
    // 检查网络连接
    if (!await this.isNetworkAvailable()) {
      console.info('网络不可用,同步操作将推迟');
      return false;
    }
    
    try {
      this.isSyncing = true;
      console.info('开始数据同步...');
      
      // 获取认证信息
      const token = await getUserToken();
      if (!token) {
        console.info('用户未登录,同步操作取消');
        return false;
      }
      
      // 处理每种实体类型的变更
      for (const [entityType, changes] of this.pendingChanges.entries()) {
        if (changes.length === 0) continue;
        
        console.info(`同步实体类型: ${entityType}, 变更数量: ${changes.length}`);
        
        // 调用API同步数据
        const success = await this.syncEntityChanges(entityType, changes, token);
        if (success) {
          // 清除已同步的变更
          this.pendingChanges.set(entityType, []);
        }
      }
      
      // 下载服务器更新
      await this.pullServerChanges(token);
      
      console.info('数据同步完成');
      return true;
    } catch (error) {
      console.error(`数据同步失败: ${error instanceof Error ? error.message : String(error)}`);
      return false;
    } finally {
      this.isSyncing = false;
    }
  }
  
  // 同步特定实体类型的变更
  private async syncEntityChanges(entityType: string, changes: any[], token: string): Promise<boolean> {
    try {
      // 根据实体类型确定API端点
      const endpoint = this.getEndpointByEntityType(entityType);
      
      // 批量提交变更
      const response = await request(
        RequestMethod.POST,
        endpoint,
        changes,
        {},
        { 'Authorization': `Bearer ${token}` }
      );
      
      console.info(`实体${entityType}同步成功, 响应: ${JSON.stringify(response)}`);
      return true;
    } catch (error) {
      console.error(`同步${entityType}失败: ${error instanceof Error ? error.message : String(error)}`);
      return false;
    }
  }
  
  // 从服务器拉取变更
  private async pullServerChanges(token: string): Promise<void> {
    try {
      // 获取最后同步时间戳
      const prefManager = PreferenceManager.getInstance();
      const lastSyncTime = await prefManager.getString('last_sync_time', '1970-01-01T00:00:00Z');
      
      // 拉取服务器变更
      const response = await request(
        RequestMethod.GET,
        '/sync/changes',
        { lastSyncTime },
        {},
        { 'Authorization': `Bearer ${token}` }
      );
      
      // 处理服务器变更
      if (response && response.changes) {
        await this.processServerChanges(response.changes);
      }
      
      // 更新最后同步时间
      await prefManager.putString('last_sync_time', getCurrentDateTime());
      
    } catch (error) {
      console.error(`拉取服务器变更失败: ${error instanceof Error ? error.message : String(error)}`);
    }
  }
  
  // 处理服务器返回的变更
  private async processServerChanges(changes: ServerChangeData): Promise<void> {
    const dbManager = DatabaseManager.getInstance();
    
    // 处理梦想更新
    if (changes.dreams && changes.dreams.length > 0) {
      for (const dream of changes.dreams) {
        const predicates = new relationalStore.RdbPredicates('dreams');
        predicates.equalTo('id', dream.id);
        
        const result = await dbManager.query(predicates);
        
        if (result.rowCount > 0) {
          // 更新已存在的梦想
          const values: relationalStore.ValuesBucket = {
            title: dream.title,
            description: dream.description,
            category: dream.category,
            target_date: dream.targetDate,
            priority: dream.priority,
            status: dream.status,
            progress: dream.progress,
            cover_image: dream.coverImage,
            updated_at: getCurrentDateTime()
          };
          await dbManager.update('dreams', values, predicates);
        } else {
          // 插入新梦想
          const values: relationalStore.ValuesBucket = {
            id: dream.id,
            user_id: dream.userId,
            title: dream.title,
            description: dream.description,
            category: dream.category,
            target_date: dream.targetDate,
            priority: dream.priority,
            status: dream.status,
            progress: dream.progress,
            cover_image: dream.coverImage,
            created_at: dream.createdAt,
            updated_at: getCurrentDateTime()
          };
          await dbManager.insert('dreams', values);
        }
        
        result.close();
      }
    }
    
    // 处理任务更新 (类似梦想处理逻辑)
    if (changes.tasks && changes.tasks.length > 0) {
      // 任务更新处理逻辑...
    }
  }
  
  // 根据实体类型获取API端点
  private getEndpointByEntityType(entityType: string): string {
    switch (entityType) {
      case 'dream':
        return '/sync/dreams';
      case 'task':
        return '/sync/tasks';
      case 'progressLog':
        return '/sync/progress-logs';
      default:
        return `/sync/${entityType}`;
    }
  }
  
  // 检查网络是否可用
  private async isNetworkAvailable(): Promise<boolean> {
    try {
      const netType = await network.getType();
      return netType !== 0; // 0表示无网络连接
    } catch (error) {
      console.error(`检查网络状态失败: ${error instanceof Error ? error.message : String(error)}`);
      return false;
    }
  }
  
  // 释放资源
  release(): void {
    this.stopPeriodicSync();
    if (this.networkObserver) {
      network.unsubscribe(this.networkObserver);
    }
  }
}

// 使用示例
export async function saveAndSyncDream(dream: Dream): Promise<number> {
  // 本地保存
  const dreamId = await saveDreamLocally(dream);
  
  // 添加到同步队列
  const syncManager = DataSyncManager.getInstance();
  syncManager.addChangeToSync('dream', { ...dream, id: dreamId });
  
  return dreamId;
}

冲突解决策略

系统实现了智能冲突解决机制:

export enum ConflictResolutionStrategy {
  LOCAL_WINS = 'LOCAL_WINS',
  SERVER_WINS = 'SERVER_WINS',
  MANUAL_RESOLVE = 'MANUAL_RESOLVE',
  MERGE = 'MERGE'
}

export class ConflictResolver {
  // 检测数据冲突
  static detectConflict(localData: any, serverData: any): boolean {
    return localData.updatedAt !== serverData.updatedAt;
  }
  
  // 解决冲突
  static async resolveConflict(
    entityType: string, 
    localData: any, 
    serverData: any, 
    strategy: ConflictResolutionStrategy = ConflictResolutionStrategy.MERGE
  ): Promise<any> {
    console.info(`解决${entityType}冲突,策略: ${strategy}`);
    
    switch (strategy) {
      case ConflictResolutionStrategy.LOCAL_WINS:
        return localData;
        
      case ConflictResolutionStrategy.SERVER_WINS:
        return serverData;
        
      case ConflictResolutionStrategy.MERGE:
        return this.mergeData(entityType, localData, serverData);
        
      case ConflictResolutionStrategy.MANUAL_RESOLVE:
        return await this.promptUserForResolution(localData, serverData);
        
      default:
        return serverData; // 默认以服务器为准
    }
  }
  
  // 合并数据
  private static mergeData(entityType: string, localData: any, serverData: any): any {
    // 基本策略:保留最新的非空值
    const merged = { ...serverData }; // 以服务器数据为基础
    
    // 根据实体类型应用特定的合并逻辑
    if (entityType === 'dream') {
      // 如果本地更新时间更新,优先使用本地字段
      if (new Date(localData.updatedAt) > new Date(serverData.updatedAt)) {
        merged.title = localData.title || merged.title;
        merged.description = localData.description || merged.description;
        merged.category = localData.category ?? merged.category;
        merged.targetDate = localData.targetDate || merged.targetDate;
        merged.priority = localData.priority ?? merged.priority;
      }
      
      // 某些字段可能需要特殊处理
      // 例如,进度取较大值
      merged.progress = Math.max(localData.progress, serverData.progress);
    }
    
    return merged;
  }
  
  // 提示用户手动解决冲突
  private static async promptUserForResolution(localData: any, serverData: any): Promise<any> {
    return new Promise((resolve) => {
      // 在实际应用中,应显示UI让用户选择或合并数据
      AlertDialog.show({
        title: '数据冲突',
        message: '本地数据和服务器数据存在冲突,请选择要保留的版本:',
        primaryButton: {
          value: '使用本地版本',
          action: () => {
            resolve(localData);
          }
        },
        secondaryButton: {
          value: '使用服务器版本',
          action: () => {
            resolve(serverData);
          }
        }
      });
    });
  }
}

数据缓存层

为提高应用性能,系统实现了高效的内存缓存:

export class MemoryCache<T> {
  private cache: Map<string, T> = new Map();
  private expiryTimes: Map<string, number> = new Map();
  private defaultTTL: number; // 生存时间,以毫秒为单位
  private maxSize: number; // 缓存最大项数
  
  constructor(defaultTTLSeconds: number = 300, maxSize: number = 100) {
    this.defaultTTL = defaultTTLSeconds * 1000;
    this.maxSize = maxSize;
    this.startCleanupTimer();
  }
  
  // 设置缓存项
  set(key: string, value: T, ttlSeconds?: number): void {
    // 如果缓存达到最大限制,移除最老项
    if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
      this.removeOldest();
    }
    
    this.cache.set(key, value);
    
    const expiry = Date.now() + (ttlSeconds ? ttlSeconds * 1000 : this.defaultTTL);
    this.expiryTimes.set(key, expiry);
  }
  
  // 获取缓存项
  get(key: string): T | undefined {
    const value = this.cache.get(key);
    
    if (value === undefined) {
      return undefined;
    }
    
    const expiry = this.expiryTimes.get(key);
    if (expiry && expiry < Date.now()) {
      this.remove(key);
      return undefined;
    }
    
    return value;
  }
  
  // 检查键是否存在
  has(key: string): boolean {
    if (!this.cache.has(key)) {
      return false;
    }
    
    const expiry = this.expiryTimes.get(key);
    if (expiry && expiry < Date.now()) {
      this.remove(key);
      return false;
    }
    
    return true;
  }
  
  // 移除缓存项
  remove(key: string): void {
    this.cache.delete(key);
    this.expiryTimes.delete(key);
  }
  
  // 清除所有缓存
  clear(): void {
    this.cache.clear();
    this.expiryTimes.clear();
  }
  
  // 移除过期项
  private cleanup(): void {
    const now = Date.now();
    for (const [key, expiry] of this.expiryTimes.entries()) {
      if (expiry < now) {
        this.remove(key);
      }
    }
  }
  
  // 移除最老的缓存项
  private removeOldest(): void {
    if (this.cache.size === 0) return;
    
    let oldestKey: string | null = null;
    let oldestExpiry = Infinity;
    
    for (const [key, expiry] of this.expiryTimes.entries()) {
      if (expiry < oldestExpiry) {
        oldestExpiry = expiry;
        oldestKey = key;
      }
    }
    
    if (oldestKey) {
      this.remove(oldestKey);
    }
  }
  
  // 启动定期清理过期项的定时器
  private startCleanupTimer(): void {
    // 每5分钟清理一次过期项
    setInterval(() => this.cleanup(), 5 * 60 * 1000);
  }
}

// 使用示例
const dreamCache = new MemoryCache<Dream>(600); // 10分钟过期

export async function getDreamById(dreamId: number): Promise<Dream> {
  // 尝试从缓存获取
  const cacheKey = `dream_${dreamId}`;
  const cachedDream = dreamCache.get(cacheKey);
  
  if (cachedDream) {
    console.info(`从缓存获取梦想: ${dreamId}`);
    return cachedDream;
  }
  
  // 从本地数据库查询
  const dream = await queryDreamFromDb(dreamId);
  
  // 添加到缓存
  if (dream) {
    dreamCache.set(cacheKey, dream);
  }
  
  return dream;
}

通过多层数据持久化策略,梦想生活规划师应用实现了高效可靠的数据管理,能够在各种网络环境下为用户提供一致的体验,同时确保用户数据的安全性和完整性。该系统的设计适应了移动应用的特殊需求,实现了高效的本地存取和智能的云端同步,为用户梦想管理提供了坚实的数据基础。

Logo

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

更多推荐