叨叨游戏网
您的当前位置:首页【中工开发者】HarmonyOS数据存储--首选项存储、关系型数据存储

【中工开发者】HarmonyOS数据存储--首选项存储、关系型数据存储

来源:叨叨游戏网


 一、首选项存储

概念及访问机制

首选项存储(Preferences):提供了轻量级配置数据的持久化能力,并支持订阅数据变化的通知能力。仅支持本地存储,常用于保存应用配置信息、用户偏好设置等。

       首选项数据存储也称为偏好数据存储或轻量级数据存储,适合于少量的数据存储,如:登录账户密码、配置信息等。 首选项数据存储具有访问速度快,存取效率高的特点。 首选项数据存储数据最终是存储在操作系统的文件中的,系统提供对底层文件读写的封装,并把底层文件映射成Preferences实例对象。

       存储访问机制,每一个底层文件对应一个Preferences实例,应用可以借助Preferences提供的接口方法,进行读写数据。 首选项数据库存储的访问机制如图所示:

代码示例

下面部分代码示例展示了一个简单的首选项存储机制,允许用户自定义界面元素的样式,并将这些设置保存到本地存储中。

注明:DevEcoStudio版本

这段代码是一个HarmonyOS应用中的首选项存储工具类PrefUtil,它使用@kit.ArkData模块中的preferences API来保存和读取应用的字体大小和颜色设置

其存储数据可以在Device File Browser - data - preferences中查看

导入相应包

import { defaultColor } from  '../pages/Index';
import { defaultSize } from '../pages/Index';
import { preferences as Pref } from '@kit.ArkData';

PreUtil.ets页面代码,该部分代码主要负责数据同步存储到本地。

const DB_NAME = 'myBb'; //存储名
const KEY_SIZE = 'keySize'; //键,存字体大小
const KEY_COLOR = 'keyColor'; //键,村字体颜色

class PrefUtil {
    // 获得Preferecnes实例,这是与本地存储交互的接口
    getFontPreferences(): Pref.Preferences {
            let options: Pref.Options =  { name: DB_NAME };
            //使用Pref.getPreferencesSync方法同步获取偏好设置
            let  pref:Pref.Preferences = Pref.getPreferencesSync( getContext(), options);
            return pref;
     }

    // 保存样式,包括大小和颜色
    saveFontStyle(fontSize: number, fontColor: string) {
        const preferences: Pref.Preferences = this.getFontPreferences();
        // 使用putSync方法同步写入数据,并调用flush方法确保数据被保存
        preferences.putSync(KEY_SIZE, fontSize);
        preferences.putSync(KEY_COLOR, fontColor);
        preferences.flush();
    }

    // 异步获得字体大小
    async getFontSize() {
        //如果本地存储中没有值,则返回默认值defaultSize
        let fontSize: number = defaultSize;
        const preferences:Pref.Preferences =  this.getFontPreferences();
        fontSize = preferences.getSync(KEY_SIZE, fontSize) as number;
        return fontSize;
    }

    // 异步获得字体颜色
    async getFontColor() {
        let fontColor: string = defaultColor;
        const preferences:Pref.Preferences =  this.getFontPreferences();
        // 从数据库中获得颜色,如果无则使用默认值
        fontColor =  preferences.getSync(KEY_COLOR, fontColor) as string;
        return fontColor;
    }
}

export default new PrefUtil(); //导出对象

Index.ets页面代码,设计页面布局。

import PrefUtil from '../common/PrefUtil'

// 默认大小和颜色
export const defaultSize: number = 50
export const defaultColor: string = '0xFF0000'

@Entry
@Component
struct Index {
  @State message: string = '首选项存储'
  @State saveSize: number = defaultSize
  @State saveColor: string = defaultColor
  @State isSave: boolean = false

  onPageShow() {
    // 显示时加载已保存的值
    PrefUtil.getFontSize().then((value) => {
      this.saveSize = value
    })
    PrefUtil.getFontColor().then((value) => {
      this.saveColor = value
    })
  }
  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(40)
          .fontWeight(FontWeight.Bold)
          .margin(20)
        Text('文本大小')
          .fontSize(26)
        TextInput({ text: '' + this.saveSize }).width('80%')
          .onChange((v) => {
            this.saveSize = Number(v)
            this.isSave = false
          })
        Text('文本颜色')
          .fontSize(26)
        TextInput({ text: this.saveColor }).width('80%')
          .onChange((v) => {
            this.saveColor = v
            this.isSave = false
          })
        Text(this.isSave ? '已保存数据' : '暂未保存').fontSize(20)
        Button("保存")
          .onClick(() => {
            // 保存大小和颜色样式
            PrefUtil.saveFontStyle(this.saveSize, this.saveColor)
            this.isSave = true
          }).width('60%').margin({ top: 10 })
        Button("恢复默认值")
          .onClick(() => {
            this.saveSize = defaultSize
            this.saveColor = defaultColor
            this.isSave = false
          }).width('60%').margin({ top: 10 })
        Text('我是首选项存储文本')
          .fontSize(this.saveSize)
          .fontColor(Number(this.saveColor))
          .margin({ top: 20 })
          .textAlign(TextAlign.Center)
      }
      .width('100%')
    }.alignItems(VerticalAlign.Top)
    .height('100%')
  }
}

二、关系型数据存储

概念及访问机制

关系型数据存储(RelationalStore):提供了关系型数据库的增删改查、加密、备份以及订阅通知等,关系型数据库是以二维表的形式进行存储数据的。支持本地存储和分布式存储,通过请DatamgrService实现分布式跨设备数据同步。

       关系型数据库(Relational Database,RDB)是基于关系模型组织管理数据的数据库。关系型数据库中一般包含若干个二维的数据表,每个表中以行和列的形式存储数据。 鸿蒙关系型数据存储底层使用SQLite作为持久化存储引擎,支持SQLite的所有数据库特性,包括事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句等。

       鸿蒙关系型数据存储框架实现了对底层SQLite数据进一步封装,对上层提供通用、完善且高效操作接口,包括一系列的增、删、改、查等。访问机制如图所示:

 代码示例

部分:关键代码

class UserAPI {
  //UserAPI 类初始化时,设置表名、列名、创建表的SQL语句,并创建 Rdb 实例来管理数据库连接。
  private tableName: string = ''
  private columns: Array<string> = []
  private rdb: Rdb | null = null
  private sql_create_table = ''

  constructor( ) {
    this.tableName = 'user'
    this.columns = ['id', 'name', 'sex', 'age', 'tel']
    this.sql_create_table = 'CREATE TABLE IF NOT EXISTS '
      + this.tableName + '('
      + 'id INTEGER PRIMARY KEY AUTOINCREMENT, '
      + 'name TEXT NOT NULL, '
      + 'sex TEXT, '
      + 'age INTEGER, '
      + 'tel TEXT)';
    this.rdb = new Rdb(this.sql_create_table)
    this.rdb.getRdbStore()
  }

  // 插入数据
  insertUser(user:User) {
    const valueBucket:relationalStore.ValuesBucket = JSON.parse(JSON.stringify(user));
    if(this.rdb?.rdbStore!=null)
    {
      this.rdb.rdbStore.insert(this.tableName, valueBucket, (err, ret) => {
        console.log('insert done: ' + ret);
        promptAction.showToast({ message: '添加用户成功!' });
      });
    }
  }

  // 根据用户名查询用户信息
  async queryUserByName(name:string) {
    let resultList:ArrayList<User> | null = null;
    let predicates = new relationalStore.RdbPredicates(this.tableName);
    predicates.equalTo('name', name);
    let ret = await this.queryFromDB(predicates);
    if( ret!=null )
    {
      resultList = this.getListFromResultSet(ret);
    }
    return resultList;
  }

  // 查询全部用户信息
  async queryUserAll() {
    let resultList:ArrayList<User> | null = null;
    let predicates = new relationalStore.RdbPredicates(this.tableName);
    let ret:relationalStore.ResultSet | null = await this.queryFromDB(predicates);

    if( ret!=null )
    {
      resultList = this.getListFromResultSet(ret);
      console.info("=====>"+resultList.convertToArray().toString());
    }
    return resultList;
  }

  // 根据条件查询数据库
  async queryFromDB( predicates:relationalStore.RdbPredicates ) {
    let resultList:relationalStore.ResultSet | null = null;
    if( this.rdb?.rdbStore!=null )
    {
      let promiseQuery = this.rdb.rdbStore.query(predicates, this.columns);
      await promiseQuery.then((resultSet) => {
        resultList = resultSet;
      }).catch((err:object) => {
        console.log("query err" + JSON.stringify(err));
      });
    }
    return resultList;
  }

  // 将查询到的结果封装用户列表
  getListFromResultSet( resultSet:relationalStore.ResultSet ) {
    let userList:ArrayList<User> = new ArrayList<User>();
    for (let i = 0; i < resultSet.rowCount; i++) {
      resultSet.goToNextRow();
      let user = new User(
      resultSet.getString(resultSet.getColumnIndex('name')),
      resultSet.getString(resultSet.getColumnIndex('sex')),
      resultSet.getLong(resultSet.getColumnIndex('age')),
      resultSet.getString(resultSet.getColumnIndex('tel')),
      resultSet.getLong(resultSet.getColumnIndex('id')) );
      userList.add(user);
    }
    return userList;
  }

  // 删除全部数据
  async deleteAll() {
    let result:number = 0;
    let predicates = new relationalStore.RdbPredicates(this.tableName);
    if(this.rdb?.rdbStore!=null)
    {
      await this.rdb.rdbStore.delete(predicates).then((rows) => {
        result = rows;
        promptAction.showToast({ message: '删除数据,rows:' + rows });
      });
    }
    return result
  }
}

三、总结 

在鸿蒙开发中,首选项存储和关系型数据存储是两种重要的数据持久化解决方案。以下是对这两种存储方式的总结:

首选项存储(Preferences)

关系型数据存储(RelationalStore)

  1. 功能特点

    • 提供关系型数据库的读写、加密、手动备份以及订阅通知的能力。
    • 可以运行自定义的SQL语句来满足复杂业务场景的需要。
    • 适用于存储复杂的数据结构,如应用内部的关系型数据。
  2. 使用场景

    • 广泛用于应用中的关系型数据的处理,包括增、删、改、查等操作。
    • 适合需要数据完整性和一致性保障的场景。
  3. 技术细节

    • 基于SQLite组件,提供了一套完整的对本地数据库进行管理的机制。
    • 支持基本数据类型:number、string、二进制类型数据、boolean。建议一条数据不要超过2M,超出该大小可能导致插入成功但读取失败。

总结来说,首选项存储适合轻量级的数据持久化需求,而关系型数据存储则适用于需要复杂查询和数据完整性保障的场景。开发者可以根据应用的具体需求选择合适的存储方案。

因篇幅问题不能全部显示,请点此查看更多更全内容