HarmonyOS应用数据持久化-KV数据库存储用户数据

331 阅读2分钟

HarmonyOS应用数据持久化-KV数据库存储用户数据

简介

本示例使用@ohos.data.distributedKVStore (分布式键值数据库)接口,持久化存储用户数据。杀死进程后重新进入app,展示退出前用户数据信息。

开发思路

  1. 参考官方KV数据库文档进行学习,发现学习路径与首选项持久化数据库雷同。都需要创建一个数据库文件,在该文件中根据标记存储数据(键值对)

  2. 设计一个KV数据库操作工具类,封装初始化kv数据库的实例对象(kvStore),使用这个对象进行增上改查。

  3. 数据库的名字(kvStoreId),要存储用户时的键名(userInfoKey),抽取到通用自定义常量文件中,方便复用和扩展。

  4. 在入口类中初始化项目,注意,注意,注意:

    经测试,要在onWindowStageCreate中初始化。在onCreate中有问题。经分析,应该是生命周期问题,但是参考官方文档后,又无法与文档相悖。无法总结其原理,只好记录于此。记下来,初始化位置选 onWindowStageCreate

  5. 在UI中使用较为简单,业务处调用工具类存储数据,aboutToAppear调用工具类获取数据。

代码编写

src/main/ets/common/DxConstants.ets

export default class DxConstants{
  // kv数据库的名字
  static readonly kvStoreId : string= "Dxin"

  //kv数据库中存储 用户数据的键名
  static readonly userInfoKey : string= "userinfo"

}

src/main/ets/common/DxKvStoreUtil.ets

import { Context } from '@kit.AbilityKit';
import { distributedKVStore } from '@kit.ArkData';
import { BusinessError } from '@kit.BasicServicesKit';

class DxKvStoreUtil {
  /*
   * KV数据库可以设计成 map 用不同的kv存储不同的数据 注意每个应用同时打开KV数据库 数量最多 16 个
   *  此处 为demo案例,未设计为 map。如果设计为map的用法,参考如下网址的首选项工具类
   *  https://juejin.cn/post/7451824088924553231
   * */
  kvStore: distributedKVStore.SingleKVStore | undefined = undefined;

  // 1. 初始化 kvstore
  async kvStoreInit(kvStoreName: string, context: Context) {
    let kvManger: distributedKVStore.KVManager | undefined = undefined

    const kvMangerConfig: distributedKVStore.KVManagerConfig = {
      context,
      bundleName: getContext(context).applicationInfo.name
    }
    kvManger = distributedKVStore.createKVManager(kvMangerConfig)
    const options: distributedKVStore.Options = {
      createIfMissing: true,
      encrypt: false,
      backup: false,
      autoSync: false,
      // kvStoreType不填时,默认创建多设备协同数据库
      kvStoreType: distributedKVStore.KVStoreType.SINGLE_VERSION,
      // 多设备协同数据库:kvStoreType: distributedKVStore.KVStoreType.DEVICE_COLLABORATION,
      securityLevel: distributedKVStore.SecurityLevel.S1
    };
    // --------------------**** 测试代码 start-------------------
    // 获取应用所有创建过的 kvStore 需要根据 BundleName

    // 此处测试代码对本示例功能无影响,纯粹想测一下 getAllKVStoreId(appid) 这个API
    // let appid = getContext(context).applicationInfo.name
    // let stroeIdArr: string [] = await kvManger.getAllKVStoreId(appid)
    // if (stroeIdArr.includes(kvStoreName)) {
    //   // 已经存在
    //   console.log("dxin => ", appid, `里已经存在${kvStoreName} kv实例`)
    // } else {
    //   console.log("dxin => ", appid, `里还没有@@存在${kvStoreName} kv实例`)
    // }
    // --------------------**** 测试代码 end-------------------

  let store =  await kvManger.getKVStore<distributedKVStore.SingleKVStore>(kvStoreName, options)
    if (store !== undefined) {
      this.kvStore = store
      console.info(`Dxin => 获取名字叫${kvStoreName}的 KVStore 成功.`);
    } else {
      console.info(`Dxin => 获取名字叫${kvStoreName}的 KVStore 失败@@.`);
    }
  }

  //   2.put 方法,注意put的数据有类型要求
  async putData(keyName: string, valueData: Uint8Array | string | number | boolean) {
    try {
      if (this.kvStore != undefined) {
        this.kvStore.put(keyName, valueData)
          .then(() => {
            console.info(`Dxin => 向${keyName} 去 put 时成功了`);
          })
          .catch((err: BusinessError) => {
            console.error(`Dxin => 向 ${keyName} 去 put 时失败了. Code:${err.code},message:${err.message}`);
          })
      }
    } catch (e) {
      let error = e as BusinessError;
      console.error(`Dxin => 向${keyName} 去 put 时发生了未知错误. Code:${error.code},message:${error.message}`);
    }
  }

  //3. 使用 kvStore 获取具体的数据
  async getData(keyName: string) {
    if (this.kvStore === undefined) {
      console.error(`Dxin => 从${keyName} 去 get 时发现,这个kv数据库都不存在`);
      return
    }
    let data = await this.kvStore.get(keyName)
    console.log(`Dxin => 从${keyName}成功获取数据. Data:${data}`)
    return data
  }

  //4. 删除 指定键名对应的数据
  deleteData(keyName: string) {
    if (this.kvStore === undefined) {
      console.error(`Dxin => 从${keyName} 去 删除数据 时发现,kv数据库都不存在`);
      return
    }
    this.kvStore.delete(keyName)
      .then(() => {
        console.info('Dxin => 成功地从${keyName}中删除数据');
      })
      .catch((err: BusinessError) => {
        console.error(`Dxin => 失败地从${keyName}中删除数据. Code:${err.code},message:${err.message}`);

      })
  }
}

export default new DxKvStoreUtil()

src/main/ets/kvstoreability/KvStoreAbility.ets

  async onWindowStageCreate(windowStage: window.WindowStage) {
     // 此处调用方法一定记得 await 等待初始化kv数据库成功再去显示UI 如果异步显示UI 会导致KV 还未初始化完呢
    // 经过测试,该方法放在 onWindowStageCreate 可行
    // 经过测试,该方法放在 onCreate 不可行 执行时机不同,生命周期只是先后顺序,并非onCreate结束后再onWindowStageCreate
     await DxKvStoreUtil.kvStoreInit(DxConstants.kvStoreId, this.context)
     console.log("Dxin => 入口类初始化了KV数据库:", DxConstants.kvStoreId)
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        return;
      }
    });
  }

src/main/ets/pages/Index.ets

import DxConstants from '../common/DxConstants';
import DxKvStoreUtil from '../common/DxKvStoreUtil';

// 用户模型
class Userinfo {
  username: string
  password: string

  constructor(username: string, password: string) {
    this.username = username
    this.password = password
  }
}

@Entry
@Component
struct Index {
  @State userinfo: Userinfo = new Userinfo("dxin", "123")

  async aboutToAppear(): Promise<void> {
    // KV数据库获取
    let userinfoStr: string = await DxKvStoreUtil.getData(DxConstants.userInfoKey) as string
    if (userinfoStr === undefined) {
      this.userinfo = new Userinfo("dd","666")
    }else {
      let currentUserinfo = JSON.parse(userinfoStr) as Userinfo
      this.userinfo = currentUserinfo
    }
  }

  build() {
    Column({ space: 30 }) {
      Text(`欢迎${this.userinfo.username},你的密码是${this.userinfo.password}`)
      TextInput({ placeholder: "用户名", text:$$this.userinfo.username })
        .onFocus(() => {
          this.userinfo.username = ""
        })
      TextInput({ placeholder: "密码", text: $$this.userinfo.password })
        .onFocus(() => {
          this.userinfo.password = ""
        })

      Button("KV数据库应用")
        .onClick(() => {
          //   KV数据库存储 注意存储的数据类型不能是对象,只能是 Uint8Array | string | number | boolean
          let userinfoStr = JSON.stringify(this.userinfo)
          DxKvStoreUtil.putData(DxConstants.userInfoKey, userinfoStr)
        })
    }
    .width('100%')
    .height('100%')

  }
}