熊熊出没 发表于 2025-3-30 09:03:53

Next版本——鸿蒙数据长期化之首选项

场景介绍

用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用长期化轻量级数据,并对其修改和查询。当用户希望有一个全局唯一存储的地方,可以采用用户首选项来举行存储。Preferences会将该数据缓存在内存中,当用户读取的时候,能够快速从内存中获取数据,当必要长期化时可以使用flush接口将内存中的数据写入长期化文件中。Preferences会随着存放的数据量越多而导致应用占用的内存越大,因此,Preferences不适合存放过多的数据,也不支持通过配置加密,适用的场景一样平常为应用保存用户的个性化设置(字体大小,是否开启夜间模式)等。
运作机制

如图所示,用户程序通过ArkTS接口调用用户首选项读写对应的数据文件。开发者可以将用户首选项长期化文件的内容加载到Preferences实例,每个文件唯一对应到一个Preferences实例,系统会通过静态容器将该实例存储在内存中,直到自动从内存中移除该实例大概删除该文件。
应用首选项的长期化文件保存在应用沙箱内部,可以通过context获取其路径。具体可见获取应用文件路径。
图1 用户首选项运作机制

https://i-blog.csdnimg.cn/img_convert/06bee70860e62c068df73ed09952d985.jpeg
束缚限定



[*] 首选项无法保证进程并发安全,会有文件损坏和数据丢失的风险,不支持在多进程场景下使用。
[*] Key键为string类型,要求非空且长度不超过1024个字节。
[*] 如果Value值为string类型,请使用UTF-8编码格式,可以为空,不为空时长度不超过16 * 1024 * 1024个字节。
[*] 内存会随着存储数据量的增大而增大,以是存储的数据量应该是轻量级的,发起存储的数据不超过一万条,否则会在内存方面产生较大的开销。
接口说明

以下是用户首选项长期化功能的相干接口,更多接口及使用方式请见用户首选项。
接口名称描述getPreferencesSync(context: Context, options: Options): Preferences获取Preferences实例。该接口存在异步接口。putSync(key: string, value: ValueType): void将数据写入Preferences实例,可通过flush将Preferences实例长期化。该接口存在异步接口。hasSync(key: string): boolean检查Preferences实例是否包罗名为给定Key的存储键值对。给定的Key值不能为空。该接口存在异步接口。getSync(key: string, defValue: ValueType): ValueType获取键对应的值,如果值为null大概非默认值类型,返回默认数据defValue。该接口存在异步接口。deleteSync(key: string): void从Preferences实例中删除名为给定Key的存储键值对。该接口存在异步接口。flush(callback: AsyncCallback<void>): void将当前Preferences实例的数据异步存储到用户首选项长期化文件中。on(type: 'change', callback: Callback<string>): void订阅数据变动,订阅的数据发生变动后,在执行flush方法后,触发callback回调。off(type: 'change', callback?: Callback<string>): void取消订阅数据变动。deletePreferences(context: Context, options: Options, callback: AsyncCallback<void>): void从内存中移除指定的Preferences实例。若Preferences实例有对应的长期化文件,则同时删除其长期化文件。 开发步调

新增/修改数据


https://i-blog.csdnimg.cn/img_convert/eed176a9ec37e63853224106f3bda3ad.png
​ import { preferences } from '@kit.ArkData'

@Entry
@Component
struct Index {
build() {
 Row() {
   Column() {
     // 1.0 利用首选项api对store这个文件做一个新增数据:["鸿蒙","HTML5"]
     Button('新增/修改数据').onClick(() => {
       //   1.0 获取store文件的操作对象
       const pre = preferences.getPreferencesSync(getContext(), { name: 'store' })

       //   2.0 调用操作对象上的putSync方法完成数据的新增 (这是将数据保存到内存中)
       pre.putSync('keyword', ["鸿蒙Next", "huawei"])
       pre.putSync('keyword2', ["HTML5", "JavaScript"])

       pre.flush() //将内存数据写入到磁盘

       AlertDialog.show({ message: '首选项数据写入成功' })
     })
   }
   .width('100%')
 }

}
}
https://i-blog.csdnimg.cn/direct/14a9752b474340f2a145b3fa9cb01701.png
结果查询:
https://i-blog.csdnimg.cn/direct/212bbf95427b49328297e259e1b9f30e.png
修改数据就还是用key值把之前数据修改成必要的就行
查询数据


https://i-blog.csdnimg.cn/img_convert/d5d747e78c80b2b861cb856b6364cd99.png
代码:

Button('获取数据').onClick(() => {
 const pre = preferences.getPreferencesSync(getContext(), { name: 'store' })
 AlertDialog.show({ message: JSON.stringify(pre.getAllSync()) })
}) https://i-blog.csdnimg.cn/direct/9410a9a60b174fd698cf891cef8b270e.png
删除数据


https://i-blog.csdnimg.cn/img_convert/bd1c094e9fc4f3fd867a5141c183647d.png
Button('删除数据').onClick(() => {
         const pre = preferences.getPreferencesSync(getContext(), { name: 'store' })
         pre.deleteSync('keyword')
         pre.flush()
         AlertDialog.show({ message: '首选项数据删除成功' })
     }) https://i-blog.csdnimg.cn/direct/105a92efd55a4a9fa95831afc295d54f.png
https://i-blog.csdnimg.cn/direct/81c265d741104d23b47a95fc06d224db.png
实例

通过一个搜刮框实例举行系统组合起来
静态结构
@Entry
@Component
struct SearchPage {
@State keyword: string = ''
@State isdel: boolean = false
aboutToAppear(): void {

}

@Builder
itemBuilder(text: string) {
 Row({ space: 20 }) {
   Text(text)
   if (this.isdel) {
     Text('x')
       .height(30)
       .onClick(() => {
         AlertDialog.show({ message: '删除' + text })
       })
   }
 }
 .margin({ right: 10, top: 10 })
 .padding({
   left: 15,
   right: 15,
   top: 5,
   bottom: 5
 })
 .backgroundColor('rgba(0,0,0,0.05)')
 .borderRadius(20)
}

build() {
 Navigation() {
   Column({ space: 15 }) {
     // 1. 搜索关键字
     TextInput({ placeholder: '输入回车保存数据', text: $$this.keyword })
       .onSubmit(() => {
         AlertDialog.show({ message: this.keyword })
       })

     // 2. 关键字列表
     Row() {
       Text('搜索记录').fontSize(20).fontWeight(800)

       Row() {
         if (this.isdel) {
           Text('全部删除')
             .onClick(()=>{
               AlertDialog.show({ message: '补上全部删除逻辑' })
             })
           Text(' | ')
           Text('取消删除')
             .onClick(()=>{
               this.isdel = false
             })
         } else {
           Text('X')
             .height(28)
             .onClick(()=>{
               this.isdel = true
             })
         }
       }
     }
     .width('100%')
     .justifyContent(FlexAlign.SpaceBetween)

     //   3. 关键字列表
     Flex({ wrap: FlexWrap.Wrap }) {
       ForEach(, (item: number) => {
         this.itemBuilder('文本' + item)
       })
     }
   }
   .padding(15)
 }
 .padding({ top: 20 })
 .titleMode(NavigationTitleMode.Mini)
 .title('搜索页面')
}
}<img alt=""src="https://i-blog.csdnimg.cn/direct/c701d153f1a74d8dba60902e304c9fce.png"/> 实现历史搜刮记录

保存关键字数组

import { preferences } from '@kit.ArkData'

@Entry
@Component
struct SearchPage {
 @State keyword: string = ''
 @State isdel: boolean = false
 @State keywords: string[] = []
 aboutToAppear(): void {
   this.getData()
}
 // 1.0 新增方法
 async saveData(text: string) {
   // 非空验证
   if(!text){
     return
 }
   // 1.0 获取首选项对象实例
   const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })
   // 2.0 调用putsync方法保存数组
   // 2.0.1 先从首选项中获取老数据
   let dataArr = pre.getSync('keyword', []) as string[]
   // 判断如果首选项中已经有了该关键词,不再保存
   if(dataArr.includes(text)){
     // 该关键字已经存在了,不保存
     return
 }

   dataArr.push(text)
   // 2.0.2 存数据
   pre.putSync('keyword', dataArr)

   // 3.0 调用flush写入到磁盘
   await pre.flush()
}
 // 2.0 获取首选项数据
 async getData() {
   const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })
   this.keywords = pre.getSync('keyword', []) as string[]
}


 @Builder
 itemBuilder(text: string) {
   Row({ space: 20 }) {
     Text(text)
     if (this.isdel) {
       Text('x')
       .height(30)
       .onClick(() => {
           AlertDialog.show({ message: '删除' + text })
       })
   }
 }
 .margin({ right: 10, top: 10 })
 .padding({
     left: 15,
     right: 15,
     top: 5,
     bottom: 5
 })
 .backgroundColor('rgba(0,0,0,0.05)')
 .borderRadius(20)
}

 build() {
   Navigation() {
     Column({ space: 15 }) {
       // 1. 搜索关键字
       TextInput({ placeholder: '输入回车保存数据', text: $$this.keyword })
       .onSubmit(async () => {

           AlertDialog.show({ message: this.keyword })
           //   将关键词数据保存到首选项中
           await  this.saveData(this.keyword)
           await this.getData()
       })

       // 2. 关键字列表
       Row() {
         Text('搜索记录').fontSize(20).fontWeight(800)

         Row() {
           if (this.isdel) {
             Text('全部删除')
             .onClick(()=>{
                 AlertDialog.show({ message: '补上全部删除逻辑' })
             })
             Text(' | ')
             Text('取消删除')
             .onClick(()=>{
                 this.isdel = false
             })
         } else {
             Text('X')
             .height(28)
             .onClick(()=>{
                 this.isdel = true
             })
         }
       }
     }
     .width('100%')
     .justifyContent(FlexAlign.SpaceBetween)

       //   3. 关键字列表
       Flex({ wrap: FlexWrap.Wrap }) {
         ForEach(this.keywords, (item: string) => {
           this.itemBuilder(item)
       })
     }
   }
   .padding(15)
 }
 .padding({ top: 20 })
 .titleMode(NavigationTitleMode.Mini)
 .title('搜索页面')
}
}
删除指定关键字/全部关键字

async delData(text?: string) {
 const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })
 //   1.0 删除全部关键
 if (!text) {
   pre.deleteSync('keyword')
 } else {
   // 2.0 删除指定关键字获取 -> 删除内存数组的关键字 -> 写回
   let datas = pre.getSync('keyword', []) as string[]
   let cindex = datas.findIndex(item => item === text)
   // 当关键字索引为-1的时候,表示没有找到
   if (cindex < 0) {
     return
   }
   // 如果有删除
   datas.splice(cindex, 1) // 返回值表示删除的元素
   //   保存回去
   pre.putSync('keyword', datas)
 }
 // 写回磁盘
 pre.flush()
}        //删除指定关键字
       await this.delData(text)
       await this.getData()
     })             // 删除全局数据
            await this.delData()
            await this.getData()
            })
完整代码
import { preferences } from '@kit.ArkData'

@Entry
@Component
struct SearchPage {
@State keyword: string = ''
@State isdel: boolean = false
@State keywords: string[] = []
aboutToAppear(): void {
    this.getData()
}
// 1.0 新增方法
async saveData(text: string) {
    // 非空验证
    if(!text){
      return
    }
    // 1.0 获取首选项对象实例
    const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })
    // 2.0 调用putsync方法保存数组
    // 2.0.1 先从首选项中获取老数据
    let dataArr = pre.getSync('keyword', []) as string[]
    // 判断如果首选项中已经有了该关键词,不再保存
    if(dataArr.includes(text)){
      // 该关键字已经存在了,不保存
      return
    }

    dataArr.push(text)
    // 2.0.2 存数据
    pre.putSync('keyword', dataArr)

    // 3.0 调用flush写入到磁盘
    await pre.flush()
}
// 2.0 获取首选项数据
async getData() {
    const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })
    this.keywords = pre.getSync('keyword', []) as string[]
}
// 3.0 删除指定关键字和全部关键字
async delData(text?: string) {
    const pre = preferences.getPreferencesSync(getContext(), { name: 'store1' })
    //   1.0 删除全部关键
    if (!text) {
      pre.deleteSync('keyword')
    } else {
      // 2.0 删除指定关键字获取 -> 删除内存数组的关键字 -> 写回
      let datas = pre.getSync('keyword', []) as string[]
      let cindex = datas.findIndex(item => item === text)
      // 当关键字索引为-1的时候,表示没有找到
      if (cindex < 0) {
      return
      }
      // 如果有删除
      datas.splice(cindex, 1) // 返回值表示删除的元素
      //   保存回去
      pre.putSync('keyword', datas)
    }
    // 写回磁盘
    pre.flush()
}


@Builder
itemBuilder(text: string) {
    Row({ space: 20 }) {
      Text(text)
      if (this.isdel) {
      Text('x')
          .height(30)
          .onClick(async () => {
            //删除指定关键字
            await this.delData(text)
            await this.getData()
            AlertDialog.show({ message: '删除' + text })
          })
      }
    }
    .margin({ right: 10, top: 10 })
    .padding({
      left: 15,
      right: 15,
      top: 5,
      bottom: 5
    })
    .backgroundColor('rgba(0,0,0,0.05)')
    .borderRadius(20)
}

build() {
    Navigation() {
      Column({ space: 15 }) {
      // 1. 搜索关键字
      TextInput({ placeholder: '输入回车保存数据', text: $$this.keyword })
          .onSubmit(async () => {

            AlertDialog.show({ message: this.keyword })
            //   将关键词数据保存到首选项中
            awaitthis.saveData(this.keyword)
            await this.getData()
          })

      // 2. 关键字列表
      Row() {
          Text('搜索记录').fontSize(20).fontWeight(800)

          Row() {
            if (this.isdel) {
            Text('全部删除')
                .onClick(async ()=>{
                  // 删除全局数据
                  await this.delData()
                  await this.getData()
                })
            Text(' | ')
            Text('取消删除')
                .onClick(()=>{
                  this.isdel = false
                })
            } else {
            Text('X')
                .height(28)
                .onClick(()=>{
                  this.isdel = true
                })
            }
          }
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)

      //   3. 关键字列表
      Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.keywords, (item: string) => {
            this.itemBuilder(item)
          })
      }
      }
      .padding(15)
    }
    .padding({ top: 20 })
    .titleMode(NavigationTitleMode.Mini)
    .title('搜索页面')
}
} 总结



[*] 该文档介绍了用户首选项数据长期化的概念、束缚和接口,并通过一个搜刮页面的实例展示了怎样使用用户首选项存储、查询、修改和删除数据。
[*] 开发者在使用时需注意数据量的控制和进程安全问题,公道利用接口实现数据的长期化操作,确保应用的正常运行和数据的一致性。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Next版本——鸿蒙数据长期化之首选项