1# 用户首选项的基本使用
2
3## 场景说明
4用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。当用户希望有一个全局唯一存储的地方,可以采用用户首选项来进行存储。用户首选项会将该数据缓存在内存中,当用户读取的时候,能够快速从内存中获取数据。用户首选项会随着存放的数据量越多而导致应用占用的内存越大,因此,用户首选项不适合存放过多的数据,适用的场景一般为应用保存用户的个性化设置(屏幕亮度,是否开启夜间模式)等。
5本例以一个小示例为大家介绍如何使用用户首选项对数据进行存储、获取、删除。
6
7## 效果呈现
8本例最终效果如下:
9
10![preference-storage](figures/preference-storage.gif)
11
12## 运行环境
13本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:
14
15- IDE: DevEco Studio 4.0 Beta1
16- SDK: Ohos_sdk_public 4.0.7.5 (API Version 10 Beta1)
17
18## 实现思路
19本例以设置屏幕亮度为例演示如何使用用户首选项管理数据,主要特性及实现方式如下:
20- 当用户在文本框输入数据后,点击保存数据,用户首选项将数据缓存在内存中:通过dataPreferences类的getPreferences方法获取用户首选项实例,然后通过该实例调用put方法将数据写入内存。
21- 当用户点击读取数据时,用户首选项将数据从内存中读取出来并显示在输入框中:通过用户首选项实例调用get方法获取到保存的数据,显示在输入框中。
22- 当用户点击删除数据时,用户首选项将数据从内存中删除,用户无法继续读取数据:通过用户首选项实例调用delete方法删除保存的数据。
23
24> ![icon-note.gif](../device-dev/public_sys-resources/icon-note.gif) **说明:**
25> 用户首选项的使用需要注意以下几点:
26> - Key键为string类型,要求非空且长度不超过80个字节。
27> - 如果Value值为string类型,请使用UTF-8编码格式,可以为空,不为空时长度不超过8192个字节。
28> - 内存会随着存储数据量的增大而增大,所以存储的数据量应该是轻量级的,建议存储的数据不超过一万条,否则会在内存方面产生较大的开销。
29
30## 开发步骤
31由于本例重点讲解用户首选项的数据管理操作,所以开发步骤会着重讲解如何通过用户首选项完成数据的存储、读取和删除,全量代码可参考完整代码章节。
321. 首先自定义一个用户首选项类,根据业务封装相关方法方便后续调用。
33    其中包含数据处理的方法,用于完成数据的存储、读取和删除操作。用户首选项接口的使用方式主要在这部分呈现,需要重点关注。
34    具体代码如下:
35    ```ts
36    import dataPreferences from '@ohos.data.preferences';
37    import promptAction from '@ohos.promptAction';
38    import ScreenBrightness from '../common/bean/Brightness';
39
40    let context = getContext(this);
41    let preference: dataPreferences.Preferences = null;
42
43    // 自定义用户首选项类
44    class PreferenceModel {
45      private brightness:ScreenBrightness
46
47      // 创建用户首选项实例preference
48      async getPreferencesFromStorage() {
49        try {
50          preference = await dataPreferences.getPreferences(context, 'setting.db');
51        } catch (err) {
52          Logger.error('[PreferenceModel]', `Failed to get preferences, Cause: ${err}`);
53        }
54      }
55
56      // 删除数据,调用dataPreferences的deletePreferences接口
57      async deletePreferences() {
58        try {
59          await dataPreferences.deletePreferences(context, 'setting.db');
60        } catch(err) {
61          Logger.error('[PreferenceModel]', `Failed to delete preferences, Cause: ${err}`);
62        };
63        preference = null;
64        this.showToastMessage($r('app.string.delete_success_msg'));
65      }
66
67      // 保存数据
68      async putPreference(screenBrightness:ScreenBrightness) {
69        if (preference === null) {
70          await this.getPreferencesFromStorage();
71        }
72        // 将用户输入的亮度数据保存到preference,调用用户首选项实例的put接口
73        try {
74          await preference.put('screenBrightness', JSON.stringify(screenBrightness));
75        } catch (err) {
76          Logger.error('[PreferenceModel]', `Failed to put value, Cause: ${err}`);
77        }
78        // 使用flush方法将preferences实例的数据存储到持久化文件,调用用户首选项实例的flush接口
79        await preference.flush();
80      }
81
82      // 获取数据,调用用户首选项实例的get接口
83      async getPreference() {
84        let screenBrightness = '';
85        if (preference === null) {
86          await this.getPreferencesFromStorage();
87        }
88        try {
89          screenBrightness = <string> await preference.get('screenBrightness', '');
90        } catch (err) {
91          Logger.error('[PreferenceModel]', `Failed to get value, Cause: ${err}`);
92        }
93        // 如果判断数据为空则提示用户先输入数据
94        if (screenBrightness === '') {
95          this.showToastMessage($r('app.string.data_is_null_msg'));
96          return;
97        }
98        this.showToastMessage($r('app.string.read_success_msg'));
99        return JSON.parse(screenBrightness);
100      }
101
102      // 校验用户输入是否为空
103      checkData(screenBrightness:ScreenBrightness) {
104        if (screenBrightness.brightSwitch === '' || screenBrightness.defaultValue === '') {
105          this.showToastMessage($r('app.string.fruit_input_null_msg'));
106          return true;
107        }
108        return false;
109      }
110
111      // 点击保存按钮保存数据
112      writeData(screenBrightness:ScreenBrightness) {
113        // Check whether the data is null.
114        let isDataNull = this.checkData(screenBrightness);
115        if (isDataNull) {
116          return;
117        }
118        // The data is inserted into the preferences database if it is not empty.
119        this.putPreference(screenBrightness);
120        this.showToastMessage($r('app.string.write_success_msg'));
121      }
122
123      // 消息弹框
124      showToastMessage(message: Resource) {
125        promptAction.showToast({
126          message: message,
127          duration: 3000
128        });
129      };
130    }
131    export default new PreferenceModel();
132    ```
1332. UI中主要包含两大部分:文本和输入框,按钮。将这两部分分别抽取为子组件,在主页中进行调用。具体代码如下:
134    文本和输入框子组件:
135    ```ts
136    import ScreenBrightness from '../common/bean/Brightness';
137
138    @Component
139    export default struct TextItemComponent {
140      private textResource: Resource;
141      private placeholderResource: Resource;
142      private marginBottom: string;
143      private marginTop: string;
144      private textInputType: InputType;
145      private textFlag: number;
146      @Link screenBrightness: ScreenBrightness;
147      private textInputCallBack: (value: string) => void;
148
149      aboutToAppear() {
150        if (this.textFlag === 0) {
151          this.marginTop = '8%';
152          this.marginBottom = '4%';
153          this.textInputType = InputType.Normal;
154        } else {
155          this.marginBottom = '321vp';
156          this.textInputType = InputType.Number;
157        }
158      }
159
160      build() {
161        Column() {
162          // 文本
163          Text(this.textResource)
164            .fontSize(25)
165            .height('3.2%')
166            .width('100%')
167            .fontColor("#182431")
168            .letterSpacing('1.58')
169            .fontWeight(500)
170            .margin({
171              bottom: '2%',
172              left: '7%',
173              top: this.marginTop
174            })
175          // 输入框
176          TextInput({
177            placeholder: this.placeholderResource,
178            text: this.textFlag === 0 ? (this.screenBrightness.brightSwitch) : (this.screenBrightness.defaultValue)
179          })
180            .placeholderFont({ size: 20, weight: 500 })
181            .placeholderColor("#BDC1C4")
182            .caretColor(Color.Blue)
183            .type(this.textInputType)
184            .height('7%')
185            .width('93%')
186            .margin({ bottom: this.marginBottom })
187            .fontSize(20)
188            .fontColor("#182431")
189            .fontWeight(500)
190            .backgroundColor("#FFFFFF")
191            .onChange((value: string) => {
192              this.textInputCallBack(value);
193            })
194        }
195      }
196    }
197    ```
198    按钮子组件:
199    ```ts
200    import PreferenceModel from '../model/PreferenceModel';
201    import ButtonItemData from '../common/bean/ButtonItemData';
202    import ScreenBrightness from '../common/bean/Brightness';
203
204    @Component
205    export default struct ButtonComponent {
206      private buttonItemValues: Array<ButtonItemData> = this.getButtonItemValues();
207      @Link screenBrightness: ScreenBrightness;
208
209      build() {
210        Column() {
211          ForEach(this.buttonItemValues, (item) => {
212            Button(item.text, { type: ButtonType.Capsule, stateEffect: true })
213              .backgroundColor("#E8A027")
214              .width('87%')
215              .height('6%')
216              .fontWeight(500)
217              .fontSize(20)
218              .margin({ bottom: '24vp' })
219              .onClick(() => {
220                item.clickMethod();
221              })
222          }, item => JSON.stringify(item))
223        }
224      }
225
226      // 在foreach中渲染Button组件时传入不同按钮的参数
227      getButtonItemValues() {
228        let values: Array<ButtonItemData> = [
229          new ButtonItemData(
230            '保存数据',
231            () => {
232              // 调用保存方法
233              PreferenceModel.writeData(this.screenBrightness);
234            }
235          ),
236          new ButtonItemData(
237            '读取数据',
238            () => {
239              // 调用读取方法
240              PreferenceModel.getPreference().then(resultData => {
241                this.screenBrightness = resultData;
242                console.info('dbdata is '+JSON.stringify(resultData))
243              });
244            }
245          ),
246          new ButtonItemData(
247            '删除数据',
248            () => {
249              // 调用删除方法
250              PreferenceModel.deletePreferences();
251              // 数据删除后将相关内容置为空
252              this.screenBrightness.brightSwitch = '';
253              this.screenBrightness.defaultValue = ''
254            }
255          )
256        ];
257        return values;
258      }
259    }
260    ```
2613. 构建首页UI。
262    在页面生命周期的aboutToAppear中调用自定义首选项类的getPreference方法获取到保存的数据,这样如果用户之前有保存数据的话,进入应用中就可以显示之前保存的数据。
263    具体代码如下:
264    ```ts
265    import PreferenceModel from '../model/PreferenceModel';
266    import ButtonComponent from '../view/ButtonComponent';
267    import TextItemComponent from '../view/TextItemComponent';
268    import ScreenBrightness from '../common/bean/Brightness';
269
270    @Entry
271    @Component
272    struct Setting {
273      @State screenBrightness: ScreenBrightness = new ScreenBrightness('', '');
274
275      build() {
276        Column() {
277          // 亮度调节文本及文本框
278          TextItemComponent({
279            textResource: $r('app.string.brightness_text'),
280            placeholderResource: $r('app.string.brightness_placeholder'),
281            textFlag: 0,
282            screenBrightness: $screenBrightness,
283            textInputCallBack: (value) => {
284              this.screenBrightness.brightSwitch = value;
285            }
286          })
287
288          // 设定值文本及文本框
289          TextItemComponent({
290            textResource: $r('app.string.defaultValue_text'),
291            placeholderResource: $r('app.string.defaultValue_placeholder'),
292            textFlag: 1,
293            screenBrightness: $screenBrightness,
294            textInputCallBack: (value) => {
295              this.screenBrightness.defaultValue = value;
296            }
297          })
298
299          // 按钮
300          ButtonComponent({ screenBrightness: $screenBrightness })
301        }
302        .width('100%')
303        .height('100%')
304        .backgroundColor("#F1F3F5")
305      }
306
307      async aboutToAppear() {
308        await PreferenceModel.getPreferencesFromStorage();
309        // 获取到之前保存的数据,显示在输入框中
310        PreferenceModel.getPreference().then(resultData => {
311          this.screenBrightness = resultData;
312        });
313      }
314    }
315    ```
316
317## 完整代码
318由于开发步骤中已经展示了大部分完整代码,此处补充前文中未呈现的两个数据类:
319亮度数据类:
320```ts
321export default class ScreenBrightness {
322  // 亮度调节
323  brightSwitch: string;
324  // 设定值
325  defaultValue: string;
326
327  constructor(brightSwitch: string, defaultValue: string) {
328    this.brightSwitch = brightSwitch;
329    this.defaultValue = defaultValue;
330  }
331}
332```
333按钮数据类:
334```ts
335export default class ButtonItemData {
336
337  // 按钮文本
338  text: string;
339
340  // 按钮点击事件触发的方法
341  clickMethod: () => void;
342
343  constructor(text: string, clickMethod: () => void) {
344    this.text = text;
345    this.clickMethod = clickMethod;
346  }
347}
348```
349
350## 参考
351- [@ohos.data.preferences (用户首选项)](../application-dev/reference/apis-arkdata/js-apis-data-preferences.md)
352- [通过用户首选项实现数据持久化](../application-dev/database/data-persistence-by-preferences.md)