1# Persisting Preferences Data
2
3
4## When to Use
5
6The **Preferences** module provides APIs for processing data in the form of key-value (KV) pairs, including querying, modifying, and persisting KV pairs. You can use **Preferences** when you want a unique storage for global data.
7
8The **Preferences** data is cached in the memory, which allows fast access when the data is required. If you want to persist data, you can use **flush()** to save the data to a file. The **Preferences** data occupies the application's memory space and cannot be encrypted through configuration. Therefore, it is recommended for storing personalized settings (font size and whether to enable the night mode) of applications.
9
10
11## Working Principles
12
13User applications call **Preference** through the ArkTS interface to read and write data files. You can load the data of a **Preferences** persistence file to a **Preferences** instance. Each file uniquely corresponds to an instance. The system stores the instance in memory through a static container until the instance is removed from the memory or the file is deleted. The following figure illustrates how **Preference** works.
14
15The preference persistent file of an application is stored in the application sandbox. You can use **context** to obtain the file path. For details, see [Obtaining Application File Paths](../application-models/application-context-stage.md#obtaining-application-file-paths).
16
17**Figure 1** Preferences working mechanism
18
19![preferences](figures/preferences.jpg)
20
21
22## Constraints
23
24- Preferences are not thread-safe and may cause file damage and data loss when used in multi-process scenarios. Do not use preferences in multi-process scenarios.
25
26- The key in a KV pair must be a string and cannot be empty or exceed 1024 bytes.
27
28- If the value is of the string type, use the UTF-8 encoding format. It can be empty or a string not longer than 16 x 1024 x 1024 bytes.
29
30- The memory usage increases with the amount of **Preferences** data. The maximum number of data records recommended is 10,000. Otherwise, high memory overheads will be caused.
31
32
33## Available APIs
34
35The following table lists the APIs used for persisting user preference data. For more information about the APIs, see [User Preferences](../reference/apis-arkdata/js-apis-data-preferences.md).
36
37| API                                                    | Description                                                        |
38| ------------------------------------------------------------ | ------------------------------------------------------------ |
39| getPreferencesSync(context: Context, options: Options): Preferences | Obtains a **Preferences** instance. This API returns the result synchronously.<br/> An asynchronous API is also provided.                   |
40| putSync(key: string, value: ValueType): void                 | Writes data to the **Preferences** instance. This API returns the result synchronously. An asynchronous API is also provided.<br/>You can use **flush()** to persist the **Preferences** instance data.|
41| hasSync(key: string): boolean                                   | Checks whether the **Preferences** instance contains a KV pair with the given key. The key cannot be empty. This API returns the result synchronously.<br/> An asynchronous API is also provided.|
42| getSync(key: string, defValue: ValueType): ValueType              | Obtains the value of the specified key. If the value is null or not of the default value type, **defValue** is returned. This API returns the result synchronously.<br/> An asynchronous API is also provided.|
43| deleteSync(key: string): void                                | Deletes a KV pair from the **Preferences** instance. This API returns the result synchronously.<br/> An asynchronous API is also provided.|
44| flush(callback: AsyncCallback&lt;void&gt;): void             | Flushes the data of this **Preferences** instance to a file for data persistence.|
45| on(type: 'change', callback: Callback&lt;string&gt;): void | Subscribes to data changes. A callback will be invoked after **flush()** is executed for the data changed.|
46| off(type: 'change', callback?: Callback&lt;string&gt;): void | Unsubscribes from data changes.                                          |
47| deletePreferences(context: Context, options: Options, callback: AsyncCallback&lt;void&gt;): void | Deletes a **Preferences** instance from memory. If the **Preferences** instance has a persistent file, this API also deletes the persistent file.|
48
49
50## How to Develop
51
521. Import the **@kit.ArkData** module.
53
54   ```ts
55   import { preferences } from '@kit.ArkData';
56   ```
57
582. Obtain a **Preferences** instance.
59
60   <!--Del-->Stage model:<!--DelEnd-->
61
62
63   ```ts
64   import { UIAbility } from '@kit.AbilityKit';
65   import { BusinessError } from '@kit.BasicServicesKit';
66   import { window } from '@kit.ArkUI';
67
68   let dataPreferences: preferences.Preferences | null = null;
69
70   class EntryAbility extends UIAbility {
71     onWindowStageCreate(windowStage: window.WindowStage) {
72       let options: preferences.Options = { name: 'myStore' };
73       dataPreferences = preferences.getPreferencesSync(this.context, options);
74     }
75   }
76   ```
77
78   <!--Del-->FA model:
79
80
81   ```ts
82   // Obtain the context.
83   import { featureAbility } from '@kit.AbilityKit';
84   import { BusinessError } from '@kit.BasicServicesKit';
85
86   let context = featureAbility.getContext();
87   let options: preferences.Options =  { name: 'myStore' };
88   let dataPreferences: preferences.Preferences = preferences.getPreferencesSync(context, options);
89   ```
90<!--DelEnd-->
91
923. Write data.
93
94   Use **putSync()** to save data to the cached **Preferences** instance. After data is written, you can use **flush()** to persist the **Preferences** instance data to a file if necessary.
95
96   > **NOTE**
97   >
98   > If the key already exists, **putSync()** overwrites the value. You can use **hasSync()** to check whether the KV pair exists.
99
100   Example:
101
102   ```ts
103   import { util } from '@kit.ArkTS';
104   if (dataPreferences.hasSync('startup')) {
105     console.info("The key 'startup' is contained.");
106   } else {
107     console.info("The key 'startup' does not contain.");
108     // Add a KV pair.
109     dataPreferences.putSync('startup', 'auto');
110     // If the string contains special characters, convert the string into a Uint8Array before storing it.
111     let uInt8Array1 = new util.TextEncoder().encodeInto("~! @#¥%......&* () --+? ");
112     dataPreferences.putSync('uInt8', uInt8Array1);
113   }
114   ```
115
1164. Read data.
117
118   Use **getSync()** to obtain the value of the specified key. If the value is null or is not of the default value type, the default data is returned.
119
120   Example:
121
122   ```ts
123   let val = dataPreferences.getSync('startup', 'default');
124   console.info("The 'startup' value is " + val);
125   // If the value is a string containing special characters, it is stored in the Uint8Array format. Convert the obtained Uint8Array into a string.
126   let uInt8Array2 : preferences.ValueType = dataPreferences.getSync('uInt8', new Uint8Array(0));
127   let textDecoder = util.TextDecoder.create('utf-8');
128   val = textDecoder.decodeToString(uInt8Array2 as Uint8Array);
129   console.info("The 'uInt8' value is " + val);
130   ```
131
1325. Delete data.
133
134   Use **deleteSync()** to delete a KV pair.<br>Example:
135
136
137   ```ts
138   dataPreferences.deleteSync('startup');
139   ```
140
1416. Persist data.
142
143   You can use **flush()** to persist the data held in a **Preferences** instance to a file.<br>Example:
144
145   ```ts
146   dataPreferences.flush((err: BusinessError) => {
147     if (err) {
148       console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
149       return;
150     }
151     console.info('Succeeded in flushing.');
152   })
153   ```
154
1557. Subscribe to data changes.
156
157   Specify an observer as the callback to return the data changes for an application. When the value of the subscribed key is changed and saved by **flush()**, the observer callback will be invoked to return the new data.<br>Example:
158
159   ```ts
160   let observer = (key: string) => {
161     console.info('The key' + key + 'changed.');
162   }
163   dataPreferences.on('change', observer);
164   // The data is changed from 'auto' to 'manual'.
165   dataPreferences.put('startup', 'manual', (err: BusinessError) => {
166     if (err) {
167       console.error(`Failed to put the value of 'startup'. Code:${err.code},message:${err.message}`);
168       return;
169     }
170     console.info("Succeeded in putting the value of 'startup'.");
171     if (dataPreferences !== null) {
172       dataPreferences.flush((err: BusinessError) => {
173         if (err) {
174           console.error(`Failed to flush. Code:${err.code}, message:${err.message}`);
175           return;
176         }
177         console.info('Succeeded in flushing.');
178       })
179     }
180   })
181   ```
182
1838. Delete a **Preferences** instance from the memory.
184
185   Use **deletePreferences()** to delete a **Preferences** instance from the memory. If the **Preferences** instance has a persistent file, the persistent file and its backup and corrupted files will also be deleted.
186
187   > **NOTE**
188   >
189   > - The deleted **Preferences** instance cannot be used for data operations. Otherwise, data inconsistency will be caused.
190   >
191   > - The deleted data and files cannot be restored.
192
193   Example:
194
195
196      ```ts
197      preferences.deletePreferences(this.context, options, (err: BusinessError) => {
198        if (err) {
199          console.error(`Failed to delete preferences. Code:${err.code}, message:${err.message}`);
200            return;
201        }
202        console.info('Succeeded in deleting preferences.');
203      })
204      ```
205
206