HarmonyOS鸿蒙Next中如何在应用中实现数据持久化存储?

HarmonyOS鸿蒙Next中如何在应用中实现数据持久化存储? 如何在鸿蒙应用中保存用户数据?如何实现数据的持久化存储和读取?

3 回复

关键字:数据存储、Preferences、持久化、本地存储、DataStorage

回答

原理解析

鸿蒙应用使用@kit.ArkData模块的preferences API实现轻量级数据持久化存储。

核心概念:

  1. Preferences:键值对存储,适合存储简单数据
  2. 数据初始化:需要在UIAbilityContext中初始化
  3. 异步操作:所有存储操作都是异步的
  4. 数据刷新:使用flush()确保数据写入磁盘

存储特点:

  • 轻量级:适合存储配置、用户偏好等小数据
  • 异步:所有操作返回Promise
  • 持久化:数据存储在应用沙箱中
  • 线程安全:支持多线程访问

详细解决步骤

步骤1:初始化Preferences

import { preferences } from '@kit.ArkData'
import { common } from '@kit.AbilityKit'

async init(context: common.UIAbilityContext) {
  this.dataPreferences = await preferences.getPreferences(
    context,
    'my_app_data'
  )
}

步骤2:保存数据

async saveData(key: string, value: string): Promise<boolean> {
  try {
    await this.dataPreferences.put(key, value)
    await this.dataPreferences.flush()
    return true
  } catch (err) {
    console.error('保存失败:', err)
    return false
  }
}

步骤3:读取数据

async getData(key: string): Promise<string | null> {
  try {
    const value = await this.dataPreferences.get(key, '')
    return value as string || null
  } catch (err) {
    console.error('读取失败:', err)
    return null
  }
}

示例代码

完整示例:数据存储服务

import { preferences } from '@kit.ArkData'
import { common } from '@kit.AbilityKit'

// 存储键名常量
export class StorageKeys {
  static readonly USER_NAME = 'user_name'
  static readonly USER_AGE = 'user_age'
  static readonly SETTINGS = 'user_settings'
  static readonly COUNTER = 'counter'
}

// 用户设置接口
export interface UserSettings {
  theme: 'light' | 'dark'
  fontSize: number
  notifications: boolean
}

// 数据存储管理类
export class DataStorage {
  private static instance: DataStorage | null = null
  private dataPreferences: preferences.Preferences | null = null
  private context: common.UIAbilityContext | null = null

  private constructor() {}

  static getInstance(): DataStorage {
    if (!DataStorage.instance) {
      DataStorage.instance = new DataStorage()
    }
    return DataStorage.instance
  }

  //初始化存储
  async init(context: common.UIAbilityContext): Promise<void> {
    this.context = context
    try {
      this.dataPreferences = await preferences.getPreferences(
        context,
        'app_data'
      )
      console.info('DataStorage initialized')
    } catch (err) {
      console.error('初始化失败:', err)
    }
  }

  //保存字符串
  async saveString(key: string, value: string): Promise<boolean> {
    return this.saveData(key, value)
  }

  //获取字符串
  async getString(key: string, defaultValue: string = ''): Promise<string> {
    const value = await this.getData(key)
    return value || defaultValue
  }

  // 保存数字
  async saveNumber(key: string, value: number): Promise<boolean> {
    return this.saveData(key, value.toString())
  }

  //获取数字
  async getNumber(key: string, defaultValue: number = 0): Promise<number> {
    const value = await this.getString(key)
    return value ? parseInt(value) : defaultValue
  }

  //保存布尔值
  async saveBoolean(key: string, value: boolean): Promise<boolean> {
    return this.saveData(key, value.toString())
  }

  // 获取布尔值
  async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {
    const value = await this.getString(key)
    return value === 'true'
  }

  // 保存对象(JSON序列化)
  async saveObject<T>(key: string, obj: T): Promise<boolean> {
    try {
      const json = JSON.stringify(obj)
      return await this.saveData(key, json)
    } catch (err) {
      console.error('保存对象失败:', err)
      return false
    }
  }

  // 获取对象(JSON反序列化)
  async getObject<T>(key: string): Promise<T | null> {
    try {
      const json = await this.getString(key)
      if (json) {
        return JSON.parse(json) as T
      }
      return null
    } catch (err) {
      console.error('获取对象失败:', err)
      return null
    }
  }

  //保存用户设置
  async saveUserSettings(settings: UserSettings): Promise<boolean> {
    return await this.saveObject(StorageKeys.SETTINGS, settings)
  }

  // 获取用户设置
  async getUserSettings(): Promise<UserSettings | null> {
    const settings = await this.getObject<UserSettings>(StorageKeys.SETTINGS)
    if (!settings) {
      // 返回默认设置
      return {
        theme: 'light',
        fontSize: 16,
        notifications: true
      }
    }
    return settings
  }

  // 删除数据
  async delete(key: string): Promise<boolean> {
    if (!this.dataPreferences) {
      return false
    }
    try {
      await this.dataPreferences.delete(key)
      await this.dataPreferences.flush()
      return true
    } catch (err) {
      console.error('删除失败:', err)
      return false
    }
  }

  //清空所有数据
  async clearAll(): Promise<boolean> {
    if (!this.dataPreferences) {
      return false
    }
    try {
      await this.dataPreferences.clear()
      await this.dataPreferences.flush()
      return true
    } catch (err) {
      console.error('清空失败:', err)
      return false
    }
  }

  //通用保存方法
  private async saveData(key: string, value: string | number): Promise<boolean> {
    if (!this.dataPreferences) {
      console.error('DataStorage未初始化')
      return false
    }
    try {
      await this.dataPreferences.put(key, value)
      await this.dataPreferences.flush()
      return true
    } catch (err) {
      console.error(`保存失败 [${key}]:`, err)
      return false
    }
  }

  //通用获取方法
  private async getData(key: string): Promise<string | null> {
    if (!this.dataPreferences) {
      console.error('DataStorage未初始化')
      return null
    }
    try {
      const value = await this.dataPreferences.get(key, '')
      return value as string || null
    } catch (err) {
      console.error(`获取失败 [${key}]:`, err)
      return null
    }
  }
}

使用示例:

import { DataStorage, StorageKeys } from '../utils/DataStorage'

@Entry
@Component
struct StorageDemo {
  @State userName: string = ''
  @State counter: number = 0
  @State settings: { theme: string, fontSize: number } | null = null
  private dataStorage = DataStorage.getInstance()

  async aboutToAppear() {
    // 需要在EntryAbility中初始化
    // await this.dataStorage.init(context)
    
    // 读取数据
    this.userName = await this.dataStorage.getString(StorageKeys.USER_NAME, '')
    this.counter = await this.dataStorage.getNumber(StorageKeys.COUNTER, 0)
    this.settings = await this.dataStorage.getObject('settings')
  }

  build() {
    Column({ space: 20 }) {
      Text('数据存储示例')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      // 用户名输入
      TextInput({ placeholder: '输入用户名', text: this.userName })
        .onChange(async (value: string) => {
          this.userName = value
          await this.dataStorage.saveString(StorageKeys.USER_NAME, value)
        })

      // 计数器
      Row({ space: 15 }) {
        Button('减少')
          .onClick(async () => {
            this.counter--
            await this.dataStorage.saveNumber(StorageKeys.COUNTER, this.counter)
          })
        
        Text(`计数: ${this.counter}`)
          .fontSize(18)
        
        Button('增加')
          .onClick(async () => {
            this.counter++
            await this.dataStorage.saveNumber(StorageKeys.COUNTER, this.counter)
          })
      }

      // 设置
      if (this.settings) {
        Text(`主题: ${this.settings.theme}`)
        Text(`字体: ${this.settings.fontSize}`)
      }

      Button('保存设置')
        .onClick(async () => {
          const newSettings = {
            theme: 'dark',
            fontSize: 18
          }
          await this.dataStorage.saveObject('settings', newSettings)
          this.settings = newSettings
        })

      Button('清空数据')
        .type(ButtonType.Normal)
        .onClick(async () => {
          await this.dataStorage.clearAll()
          this.userName = ''
          this.counter = 0
          this.settings = null
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .backgroundColor('F1F3F5')
  }
}

高级用法

  1. 在EntryAbility中初始化
import { dataStorage } from './utils/DataStorage'

export default class EntryAbility extends UIAbility {
  onWindowStageCreate(windowStage: window.WindowStage): void {
    // 初始化数据存储
    dataStorage.init(this.context).then(() => {
      windowStage.loadContent('pages/Index')
    })
  }
}
  1. 数据加密存储
// 使用加密库对敏感数据进行加密
import { cipher } from '@kit.CryptoArchitectureKit'

async saveEncrypted(key: string, value: string): Promise<boolean> {
  const encrypted = await cipher.encrypt(value)
  return await this.saveString(key, encrypted)
}
  1. 数据迁移
async migrateData(): Promise<void> {
  const oldVersion = await this.getNumber('data_version', 1)
  if (oldVersion < 2) {
    // 执行数据迁移逻辑
    await this.saveNumber('data_version', 2)
  }
}

常见问题

Q: 数据存储在哪里? A: 数据存储在应用沙箱的/data/app/el2/100/base/com.example.app/database/目录下。

Q: 如何存储大量数据? A: 对于大量数据,建议使用关系型数据库(RDB)或对象关系映射数据库(ORM)。

Q: 数据会跨应用共享吗? A: 不会,每个应用的数据存储在独立的沙箱中,无法跨应用访问。

总结:Preferences是轻量级数据存储的最佳选择,掌握其使用方法和最佳实践是开发持久化应用的基础。

更多关于HarmonyOS鸿蒙Next中如何在应用中实现数据持久化存储?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,数据持久化存储主要通过以下方式实现:

  1. 轻量级偏好数据库:适用于键值对数据存储,通过Preferences类进行数据读写。

  2. 关系型数据库:使用RDB(Relational Database)存储结构化数据,支持SQLite操作。

  3. 分布式数据对象:通过DistributedDataObject实现跨设备数据同步。

  4. 文件系统:使用FileManagerFileIO API进行文件读写操作。

开发者可根据数据类型和访问需求选择相应方案,所有存储操作均需在应用沙箱内进行。

在HarmonyOS Next中,实现应用数据持久化存储主要有以下几种核心方式,开发者可根据数据特性(如结构化程度、安全要求、访问频率)选择:

  1. 首选项(Preferences)

    • 适用场景:存储轻量级的键值对数据,如用户设置、应用配置。
    • 实现方式:通过@ohos.data.preferences模块创建Preferences实例,使用put()get()flush()等方法进行存取。数据以文件形式保存在应用沙箱内。
    • 特点:非关系型,基于KV结构,支持数据变更监听。
  2. 关系型数据库(RelationalStore)

    • 适用场景:存储结构化、需要复杂查询的数据,如用户通讯录、交易记录。
    • 实现方式:使用@ohos.data.relationalStore模块,通过SQLite引擎实现。需定义RdbStore实例,利用SQL语句或链式接口(如Predicates)进行增删改查。
    • 特点:支持事务、数据加密,可通过数据同步框架跨设备流转。
  3. 对象关系映射(ORM)

    • 适用场景:在关系型数据库基础上,希望通过对象化接口操作数据,简化开发。
    • 实现方式:基于@ohos.data.relationalStore,通过@Entry@PrimaryKey等装饰器定义实体类,使用OrmContext进行对象化操作。
    • 特点:将数据库表映射为TypeScript/ArkTS类,提升代码可读性。
  4. 分布式数据对象(DataObject)

    • 适用场景:需要在同一应用的不同UIAbility实例间,或跨设备间同步内存中的对象状态。
    • 实现方式:使用@ohos.data.distributedDataObject模块创建DataObject实例,对其属性的修改会自动在绑定对象间同步。
    • 特点:数据存储在内存中,生命周期跟随应用或绑定关系,适用于临时状态同步。
  5. 文件系统

    • 适用场景:存储非结构化数据,如图片、音频、文档或需要自定义格式的大数据块。
    • 实现方式:通过@ohos.file.fs等文件管理接口,在应用沙箱目录(如dirs.data)或公共媒体目录进行文件读写。
    • 特点:最灵活的存储方式,需自行管理数据格式与IO操作。

选择建议

  • 简单配置:用首选项
  • 结构化数据、复杂查询:用关系型数据库ORM
  • 跨UIAbility或跨设备状态同步:用分布式数据对象
  • 非结构化数据或自定义格式:用文件系统

所有持久化数据默认存储在应用沙箱内,保障安全与隐私。跨设备同步需结合分布式数据管理框架,并确保设备已组网且用户授权。

回到顶部