用户首选项(Preferences)
- 通常用于保存应用的配置信息。数据通过文本的形式保存在设备中,应用使用过程中会将文本中的数据全量加载到内存中,所以访问速度快、效率高,但不适合需要存储大量数据的场景。
Preferences会随着存放的数据量越多而导致应用占用的内存越大,因此,Preferences不适合存放过多的数据,建议存储的数据不超过一万条- 适用的场景一般为应用保存用户的个性化设置(字体大小,是否开启夜间模式)等。
简介
本示例使用@ohos.data.preferences 接口,展示了使用首选项持久化存储数据的功能。
持久化主题
效果预览
| default主题 | grey主题 | simplicity主题 |
|---|---|---|
使用说明
1.点击顶部titleBar的右侧切换按钮,弹出主题菜单,选择任意主题则切换相应的主题界面;
2.退出应用再重新进入,显示上一次退出前的主题界面。
开发步骤
1. 准备常量数据
- 三种主题名称组成的数组
- 三种主题数据:图标
icon和对应name - 存储主题数据的时候 要指定首选项对象即文件(数据库)名称
一个项目可以有使用一个首选项对象存数据,也可以使用多个首选项文件分开存不同的数据。建议分门别类设计。
- 存储主题的时候,需要设计一个key值
一个首选项对象(文件)可以存很多个键值对数据。根据key区分。
export interface ImageAndName {
image: string;
name: string;
}
import { ImageAndName } from "../model/ImageAndName"
export default class DxConstants{
// 三种主题的名称
static readonly THEME_NAMES:string[] = ['default','grey','Simple']
// 三种主题数据
static readonly themeDataArr: ImageAndName[][] = [
[
{ image: "/image/model1/dialer.png", name: "dianhua" },
{ image: "/image/model1/shopping.png", name: "shangcheng" },
{ image: "/image/model1/notes.png", name: "beiwanglu" },
{ image: "/image/model1/settings.png", name: "shezhi" },
{ image: "/image/model1/camera.png", name: "xiangji" },
{ image: "/image/model1/gallery.png", name: "xiangce" },
{ image: "/image/model1/music.png", name: "yinyue" },
{ image: "/image/model1/video.png", name: "shipin" },
],
[
{ image: "/image/model2/simplicityCall.png", name: "dianhua" },
{ image: "/image/model2/simplicityShop.png", name: "shangcheng" },
{ image: "/image/model2/simplicityNotes.png", name: "beiwanglu" },
{ image: "/image/model2/simplicitySetting.png", name: "shezhi" },
{ image: "/image/model2/simplicityCamera.png", name: "xiangji" },
{ image: "/image/model2/simplicityPhotos.png", name: "xiangce" },
{ image: "/image/model2/simplicityMusic.png", name: "yinyue" },
{ image: "/image/model2/simplicityVideo.png", name: "shipin" },
],
[
{ image: "/image/model3/pwcall.png", name: "dianhua" },
{ image: "/image/model3/pwshop.png", name: "shangcheng" },
{ image: "/image/model3/pwnotes.png", name: "beiwanglu" },
{ image: "/image/model3/pwsetting.png", name: "shezhi" },
{ image: "/image/model3/pwcamera.png", name: "xiangji" },
{ image: "/image/model3/pwphotos.png", name: "xiangce" },
{ image: "/image/model3/pwmusic.png", name: "yinyue" },
{ image: "/image/model3/pwvideo.png", name: "shipin" },
]
]
// 存储主题的首选项的 文件(数据库)名称
static readonly PREFERENCES_THEME:string = "theme.db"
// 存储主题的时候 key
static readonly THEME_KEY:string = "themeModel"
}
2. 准备首选项工具类
- 设计成
map数据结构,方便存多种首选项文件对象。后期存主题时,使用一个首选项对象,存字体大小时,可以使用另一个。如有其他需要使用不同的首选项对象时,灵活扩展。 - 首选项对象创建需要上下文对象和该文件数据库的
name。设计好loadPreference()方法,创建好首选项对象后加入到map中。 - 设计保存数据和获取数据的方法。
既然设计逻辑为该项目有多个首选项对象,那么在 保存/获取 数据的时候就需要确定从 哪个首选项对象 身上 存储/获取 哪个key
// 首选项工具栏,提供首选项增上改查功能
import { preferences } from '@kit.ArkData'
import { Context } from '@ohos.arkui.UIContext'
class PreferencesUtil {
// 准备一个map, 用来存多个首选项对象
preMap: Map<string, preferences.Preferences> = new Map()
// 加载 首选项对象
loadPreference(context: Context, name: string) {
try {
// 该接口 第二个参数 在next修改为配置项 而非字符串
let pre: preferences.Preferences = preferences.getPreferencesSync(context, { name })
// 存到首选项 map中
this.preMap.set(name, pre)
console.log('PreferencesUtil', `加载Preferences【${name}】成功`)
} catch (e) {
console.log('PreferencesUtil', `加载Preferences【${name}】失败`, JSON.stringify(e))
}
}
// 保存数据
putPreferenceVal(preferenceName: string, key: string, value: preferences.ValueType) {
if (!this.preMap.has(preferenceName)) {
console.log('PreferencesUtil', `加载Preferences【${preferenceName}】尚未初始化`)
return
}
try {
// 从数组中获取该首选项对象
let pref = this.preMap.get(preferenceName)
// 写入数据
pref?.putSync(key, value)
// 刷盘
pref?.flush()
console.log('PreferencesUtil', `保存【${preferenceName}】-【${key}】-【${value}】成功`)
} catch (e) {
console.log('PreferencesUtil', `保存【${preferenceName}】-【${key}】-【${value}】失败`, JSON.stringify(e))
}
}
// 获取数据
getPreferenceVal(preferenceName: string, key: string, defaultVal: preferences.ValueType){
if (!this.preMap.has(preferenceName)) {
console.log('PreferencesUtil', `加载Preferences【${preferenceName}】尚未初始化`)
return
}
try {
let pref = this.preMap.get(preferenceName)
let val = pref?.getSync(key, defaultVal)
console.log('PreferencesUtil', `读取【${preferenceName}】-【${key}】-【${val}】成功`)
return val
}catch (e){
console.log('PreferencesUtil', `读取【${preferenceName}】-【${key}】失败`,JSON.stringify(e))
// try和catch都要有返回
return defaultVal
}
}
}
export default new PreferencesUtil()
3. 入口类中创建首选项对象
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 初始化首选项
let context = this.context
// 存储主题的 首选项文件放到 map中
PreferencesUtil.loadPreference(context,DxConstants.PREFERENCES_THEME)
}
4. 在UI中使用
- 切换主题:在首页预先设置好几套主体数据,使用
preferences.getPreferences获取使用Preferences对象,调用Preferences.get()读取缓存中的参数,得到当前应该展示哪一套主体。每次点击切换按钮都会调用Preferences.put()来重新修改参数,然后使用Preferences.flush()保存并刷新文件内容。 源码参考:Index.ets 。
import DxConstants from "../common/DxConstants";
import PreferencesUtil from "../common/PreferencesUtil";
import { ImageAndName } from "../model/ImageAndName";
@Entry
@Component
struct Index {
@StorageProp("info") message: string = ""
// 当前页面展示的数据
@State theme: ImageAndName[] = DxConstants.themeDataArr[0]
@State themeName: string = DxConstants.THEME_KEY[0]
// 页面加载先查看上一次的主题是什么
aboutToAppear(): void {
this.themeName = PreferencesUtil.getPreferenceVal(
DxConstants.PREFERENCES_THEME,
DxConstants.THEME_KEY,
DxConstants.THEME_NAMES[0]
) as string
// 根据 modelName 获取索引值
let index = DxConstants.THEME_NAMES.indexOf(this.themeName)
// 初始化当前模型数组
this.theme = DxConstants.themeDataArr[index]
}
// 修改当前显示模式
changeTheme(index: number) {
// 主题名称
this.themeName = DxConstants.THEME_NAMES[index]
// 主题数组
this.theme = DxConstants.themeDataArr[index]
// 持久化存储
PreferencesUtil.putPreferenceVal(
DxConstants.PREFERENCES_THEME,
DxConstants.THEME_KEY,
DxConstants.THEME_NAMES[index]
)
}
build() {
Column({ space: 30 }) {
Text(this.message).fontColor("#fff50909")
Divider().color(Color.Red)
Row() {
Text("主题:"+this.themeName)
.fontSize(20)
.layoutWeight(5)
.padding({ left: 10 })
.fontColor(Color.White)
.fontWeight(FontWeight.Bold)
Image($r('app.media.change'))
.key('changeBtn')
.id('changeBtn')
.height(30)
.layoutWeight(1)
.objectFit(ImageFit.ScaleDown)
.bindMenu([
{
value: DxConstants.THEME_NAMES[0],
action: () => {
// change and save model0 :default
this.changeTheme(0)
}
},
{
value: DxConstants.THEME_NAMES[1],
action: () => {
// change and save model1 :simplicity
this.changeTheme(1)
}
},
{
value: DxConstants.THEME_NAMES[2],
action: () => {
// change and save model2 :pomelo
this.changeTheme(2)
}
}
])
}
.width('100%')
.height(50)
.backgroundColor('#0D9FFB')
Grid() {
ForEach(this.theme, (item: ImageAndName) => {
GridItem() {
Column() {
Image(item.image)
.width(70)
.height(70)
.padding(10)
.objectFit(ImageFit.Fill)
Text(item.name).fontSize(15)
}
.width(90)
.height(90)
}
}, (item: ImageAndName) => JSON.stringify(item))
}
.rowsGap(10)
.width('100%')
.columnsGap(10)
.layoutWeight(1)
.padding({ top: 20 })
.backgroundColor('#e5e5e5')
.columnsTemplate('1fr 1fr 1fr 1fr')
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.theme_color'))
}
}
持久化字号大小(缩放倍数)。
在前文持久化主题数据掌握后,顺便持久化一下字号大小。 项目源码
设计思路
- 入口类初始化一个新的首选项数据库文件,例如取名:
fontSize.db - 准备状态变量绑定到滑块Slider身上, 滑块通过
onChange事件修改当前状态变量数据,双向更新。 - 在滑块
onChange事件中持久化存储 - 在
aboutToAppear函数中获取持久化的字号大小放大倍数
编码过程
- 在
src/main/ets/common/DxConstants.ets文件中追加常量数据
// 存储字号大小的 数据库 名称
static readonly PREFERENCES_FontSize:string = "fontSizeScale.db"
// 存储字号大小 倍数 的时候 key
static readonly FONTSIZE_KEY:string = "fontSizeScale"
// 字号大小 倍数 默认值
static readonly fontSizeScaleDefault : number= 1
- 在入口类
src/main/ets/preferencesability/PreferencesAbility.ets中初始化首选项数据库文件
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
console.log("dxin => PreferencesAbility is Created")
// 获取主模块传递过来的参数
let abilityWant = want
let info = abilityWant?.parameters?.info || '首选项'
AppStorage.setOrCreate("info", info)
// 初始化首选项
let context = this.context
// 存储主题的 首选项文件放到 map中
PreferencesUtil.loadPreference(context, DxConstants.PREFERENCES_THEME)
// 存储字号大小的 首选项文件 放到 map 中
PreferencesUtil.loadPreference(context, DxConstants.PREFERENCES_FontSize)
}
- 在UI中使用
-
- 定义状态变量
@State currentSliderVal: number = DxConstants.fontSizeScaleDefault
-
- 页面加载前初始化状态变量
aboutToAppear(): void {
// 去查询一下 上次存储的 字号大小数据 数据
this.currentSliderVal = PreferencesUtil.getPreferenceVal(
DxConstants.PREFERENCES_FontSize,
DxConstants.FONTSIZE_KEY,
DxConstants.fontSizeScaleDefault
) as number
}
-
- 在页面中添加滑块组件
Column() {
Row() {
Text(0.8 + "").fontSize(20)
Text(this.currentSliderVal.toFixed(1)).fontSize(30).fontColor("#fff50065")
Text(1.2 + "").fontSize(20)
}
.width("80%")
.height(40)
.justifyContent(FlexAlign.SpaceBetween)
Slider({
min: 0.8,
max: 1.2,
step: 0.1,
value: this.currentSliderVal
})
.width("80%")
.height(40)
.onChange((val) => {
this.currentSliderVal = val
// 把当前改变的数据,存储起来 持久化
PreferencesUtil.putPreferenceVal(
DxConstants.PREFERENCES_FontSize,
DxConstants.FONTSIZE_KEY,
this.currentSliderVal
)
console.log("dxin => 存储好了字号大小:", this.currentSliderVal)
})
}
-
- 页面中用到文字的地方,进行字号大小的设置:
字号*倍数
- 页面中用到文字的地方,进行字号大小的设置:
Text(item.name).fontSize(16 * this.currentSliderVal)
键值型数据库(KV-Store)
HarmonyOS应用数据持久化-KV数据库存储用户数据
- 设备协同数据库,针对每条记录,Key的长度≤896 Byte,Value的长度<4 MB。
- 单版本数据库,针对每条记录,Key的长度≤1 KB,Value的长度<4 MB。
- 每个应用程序最多支持同时打开16个键值型分布式数据库。
- 键值型数据库事件回调方法中不允许进行阻塞操作,例如修改UI组件。
- 存储的数据类型不能是对象,只能是
Uint8Array|string|number|boolean
简介
本示例使用@ohos.data.distributedKVStore (分布式键值数据库)接口,持久化存储用户数据。杀死进程后重新进入app,展示退出前用户数据信息。
开发思路
- 参考官方KV数据库文档进行学习,发现学习路径与首选项持久化数据库雷同。都需要创建一个数据库文件,在该文件中根据标记存储数据(键值对)
- 设计一个KV数据库操作工具类,封装初始化kv数据库的实例对象
(kvStore),使用这个对象进行增上改查。 - 数据库的名字
(kvStoreId),要存储用户时的键名(userInfoKey),抽取到通用自定义常量文件中,方便复用和扩展。 - 在入口类中初始化项目,注意,注意,注意:
经测试,要在onWindowStageCreate中初始化。在onCreate中有问题。经分析,应该是生命周期问题,但是参考官方文档后,又无法与文档相悖。无法总结其原理,只好记录于此。记下来,初始化位置选 onWindowStageCreate
- 在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%')
}
}
关系型数据库(RelationalStore)
以书籍信息为例完成增删改查。使用关系型数据库操作数据。掌握该案例后,可举一反三设计开发记账本项目、便单项目、等各种常见app类似功能。
开发思路
- 封装工具类,设计初始化rdb实例方法(涉及到ability的上下文对象),供增上改查方法中使用该实例对象
- 入口类中初始化rdb实例对象
- UI处设计业务逻辑进行增删改查
代码编写
常量类
export default class DxConstants {
//rdbstore 数据库的名称 根据业务自定义,此处为学习demo,随便取
static readonly rdbStoreName: string = 'DxRdbStore'
// ------------------dxBook 表-----------
static readonly bookTableName: string = 'dxBook'
static readonly SQL_CREATE_TABLE_Book =
`CREATE TABLE IF NOT EXISTS dxBook (
ID INTEGER PRIMARY KEY AUTOINCREMENT,
NAME TEXT NOT NULL,
price INTEGER
)`
}
书籍数据库工具类
import { relationalStore, ValuesBucket } from "@kit.ArkData"
import Book from "../model/Book";
import DxConstants from "./DxConstants";
class BookRdbUtil {
// Book表 增删改查 都要用到的 rdb对象 可以在入口类调用方法初始化(因为需要上下文对象)
bookRdbStore: relationalStore.RdbStore | undefined = undefined
// 初始化方法
async initRdbStore(context: Context) {
// 设置当前数据库配置信息
const STORE_CONFIG: relationalStore.StoreConfig = {
name: DxConstants.bookTableName, // 数据库文件名
securityLevel: relationalStore.SecurityLevel.S3, // 数据库安全级别
}
let rdbStore = await relationalStore.getRdbStore(context, STORE_CONFIG)
rdbStore.executeSql(DxConstants.SQL_CREATE_TABLE_Book)
this.bookRdbStore = rdbStore
// console.log(`dxin => bookRdbStore初始化OK ${this.bookRdbStore}`)
}
// 增
add(book: Book) {
/*
*
* */
if (this.bookRdbStore != undefined) {
/*
* param1: 往哪个表中插入数据
* param2: 插入什么数据
* return : 插入后影响的行数
* */
return this.bookRdbStore.insertSync(DxConstants.bookTableName, { name: book.name, price: book.price })
} else {
console.log(`dxin => 插入数据失败, ${DxConstants.bookTableName}对应的rdbstore是undefined`)
return -1
}
}
// 删
delBookById(id: number) {
if (this.bookRdbStore != undefined) {
let predicates = new relationalStore.RdbPredicates(DxConstants.bookTableName) // 获取谓词对象
predicates.equalTo('id', id) // 匹配规则
return this.bookRdbStore.deleteSync(predicates)
} else {
console.log(`dxin => ${DxConstants.bookTableName}表删除数据时出错,数据库 undefined ,或者谓词 undefined`)
return -1
}
}
// 改
/*
* 修改方法 根据ID 更新为新的 Book对象数据
* predicatesName:创建表表的谓词 需要确定该字符串
* field: 更新哪个字段
* fieldVal:匹配该字段的哪一个值
* newVal:当前行的新数据
*
* 返回值: 修改语句影响的行数 number
* */
update(book:Book) {
// 修改数据
if ( this.bookRdbStore != undefined) {
let predicates = new relationalStore.RdbPredicates(DxConstants.bookTableName)
predicates.equalTo('id', book.id);
// 定义一个 ValuesBucket 数据
let newBook:ValuesBucket={
id:book.id || 0,
name:book.name,
price:book.price
}
return this.bookRdbStore.updateSync(newBook, predicates)
} else {
console.log(`dxin => 修改数据时出错,数据库 undefined `)
return -1
}
}
// 查所有
queryAllBook() {
let predicates = new relationalStore.RdbPredicates(DxConstants.bookTableName) // 获取谓词对象
let bookArr = this.getBookArr(predicates)
return bookArr
}
// 条件查询 根据书名查询
queryBookByName(name: string) {
let predicates = new relationalStore.RdbPredicates(DxConstants.bookTableName) // 获取谓词对象
predicates.equalTo('name', name)
let bookArr = this.getBookArr(predicates)
return bookArr
}
// 条件查询 根据价格查询
queryBookByPrice(price: number) {
let predicates = new relationalStore.RdbPredicates(DxConstants.bookTableName) // 获取谓词对象
predicates.equalTo('price', price)
let bookArr = this.getBookArr(predicates)
return bookArr
}
// book遍历字段封装数组功能
getBookArr(predicates: relationalStore.RdbPredicates): Book[] {
if (this.bookRdbStore != null) {
let result = this.bookRdbStore.querySync(predicates)
let bookArr: Book[] = []
while (!result.isAtLastRow) {
result.goToNextRow()
let id = result.getLong(result.getColumnIndex('id'))
let name = result.getString(result.getColumnIndex('name'))
let price = result.getLong(result.getColumnIndex('price'))
bookArr.unshift(new Book(name, price, id))
}
result.close() // 释放数据集内存
return bookArr
} else {
console.log(`dxin => ${DxConstants.bookTableName}表查询数据时出错,数据库 undefined ,或者谓词 undefined`)
return [new Book("查询错误", 0, 0)]
}
}
}
export default new BookRdbUtil()
入口类
onWindowStageCreate(windowStage: window.WindowStage): void {
// 初始化BookRdbUtil 中的 bookRdbStore
BookRdbUtil.initRdbStore(this.context)
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
return;
}
});
}
书籍增删改查页面
import Book from '../model/Book';
import BookRdbUtil from '../common/BookRdbUtil';
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct BookCurd {
@State title: string = '使用工具类操作book表数据';
// book数组数据
@State bookArr: Book[] = []
// 待存入 书籍对象
@State insertBookData: Book = new Book('帝心', 19)
// 待查询的书名
@State queryName: string = '红楼梦'
// 待查询的价格
@State queryPrice: number = 99
// 待修改的数据
@State editBookObj: Book = new Book('待修改',0)
aboutToAppear(): void {
this.showBookArrData()
}
// 数据回显到页面上
showBookArrData() {
this.bookArr = BookRdbUtil.queryAllBook()
}
// 弹窗id
customDialogComponentId: number = 0
// 弹窗布局
@Builder
editBook() {
Column() {
TextInput({ text: $$this.editBookObj.name })
.fontSize(22).width("70%")
.backgroundColor('#c6805b5b')
.borderRadius(5)
TextInput({ text: $$this.editBookObj.price})
.fontSize(22).width("70%")
.backgroundColor('#a4915c5c')
.borderRadius(5)
Button('修改')
.width('70%')
.onClick(() => {
// 咋拿到 上方输入框新数据 去操作数据库
BookRdbUtil.update(this.editBookObj) // 更新
this.showBookArrData() // 查询回显
promptAction.closeCustomDialog(this.customDialogComponentId)
})
}
.height('30%')
.borderRadius(5)
.justifyContent(FlexAlign.SpaceAround)
}
build() {
Column({ space: 10 }) {
Text(this.title).fontSize(30)
Divider().color(Color.Red)
// 功能区
Row() {
// 插入
Column() {
TextInput({ placeholder: "请输入书名", text: $$this.insertBookData.name }).width("100%")
.onFocus(() => {
this.insertBookData.name = ''
})
TextInput({ placeholder: "价格", text: $$this.insertBookData.price }).width("100%")
.onFocus(() => {
this.insertBookData.price = 0
})
Button('插入')
.width("50%")
.type(ButtonType.Normal)
.borderRadius(10)
.onClick(() => {
let rows = BookRdbUtil.add(this.insertBookData)
if (rows != -1) {
console.log(`dxin => insert result ${`插入数据OK了`}`)
// 插入成功后 数据回显
this.showBookArrData()
} else {
console.log(`dxin => insert result ${`插入数据出错了`}`)
}
})
}
.width("40%")
.height('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.alignItems(HorizontalAlign.Center)
.backgroundColor('#88acd0ef')
// 查询
Column() {
// 根据名字查询
Row() {
TextInput({ placeholder: "待查书名", text: $$this.queryName }).width("50%")
.onFocus(() => {
this.queryName = ''
})
.onBlur(() => {
this.queryName = ''
})
Button('查by书名')
.width("40%")
.type(ButtonType.Normal)
.borderRadius(10)
.onClick(() => {
let bookArr = BookRdbUtil.queryBookByName(this.queryName)
this.bookArr = bookArr
})
}
.width("100%")
.justifyContent(FlexAlign.SpaceAround)
// 根据价格查询
Row() {
TextInput({ placeholder: "待查价格", text: $$this.queryPrice })
.width("50%")
.onFocus(() => {
this.queryPrice = 0
})
.onBlur(() => {
this.queryPrice = 0
})
Button('查by价格')
.width("40%")
.type(ButtonType.Normal)
.borderRadius(10)
.onClick(() => {
let bookArr = BookRdbUtil.queryBookByPrice(this.queryPrice)
this.bookArr = bookArr
})
}
.width("100%")
.justifyContent(FlexAlign.SpaceAround)
}
.width("60%")
.height('100%')
.justifyContent(FlexAlign.SpaceAround)
.alignItems(HorizontalAlign.Center)
.backgroundColor('#3c96ef6c')
}
.width("100%")
.height(150)
.justifyContent(FlexAlign.SpaceEvenly)
Divider().color(Color.Red)
if (this.bookArr.length == 0) {
Text('无可展示数据')
.fontSize(30)
.width(30)
}
List({ space: 5 }) {
ForEach(this.bookArr, (item: Book) => {
ListItem() {
Row() {
Button('修改')
.width(60)
.height(30)
.fontSize(12)
.fontColor('#ff11e2c3')
.backgroundColor('#94ffffff')
.onClick(() => {
//todo 弹窗修改数据
this.editBookObj = item
// 先准备一个弹窗对象
promptAction.openCustomDialog({
builder: () => {
this.editBook()
}
}).then((id) => {
this.customDialogComponentId = id
})
})
Text(`id:${item.id}`)
Text(`name:${item.name}`)
Text(`price:${item.price}`)
Button('del')
.width(60)
.height(30)
.fontSize(12)
.fontColor('#ffff0000')
.backgroundColor('#94ffffff')
.onClick(() => {
let rows = BookRdbUtil.delBookById(Number(item.id))
if (rows != 0) {
this.showBookArrData()
} else {
console.log(`dxin => insert del ${`删除数据出错了`}`)
}
})
}
.width("100%")
.justifyContent(FlexAlign.SpaceEvenly)
}.width("100%")
})
}
.width("100%")
.layoutWeight(1)
.divider({ strokeWidth: 1, color: '#fff39b9b' })
}
.width('100%')
.height('100%')
}
}