How to persistently store object-type data on a hard drive using PersistentStorage
Problem Description
PersistentStorage itself does not support the storage of object or array types. How can data be processed to meet the storage requirements and enable the storage of object and array types?
Background Knowledge
- AppStorage: This is the application-wide UI state storage, which is bound to the application's process. It is created by the UI framework when the application starts, providing a central storage for the application's UI state properties.
- PersistentStorage: This is the persistent storage of selected AppStorage properties, ensuring that these properties retain their values upon application restart, matching the values at the time of application closure.
Since PersistentStorage allows simple types such as number, string, boolean, and enum, it is considered to convert to string type for storage. JSON.stringify() can convert an object or value into a JSON string, so we can attempt to use this method to convert it into a string before storing it.
Troubleshooting Process
- Identify Issue: PersistentStorage only supports primitive types (number, string, boolean, enum). Objects/arrays cause errors.
-
Serialize Data: Convert objects/arrays to JSON strings using
JSON.stringify()before storage. -
Deserialize Data: On retrieval, parse strings back to objects/arrays with
JSON.parse()(add error handling). -
Reactivity: Use
@StorageLinkfor UI updates when stored data changes.
Analysis Conclusion
Solution: Serialize objects/arrays to JSON strings via JSON() for storage, then deserialize with JSON.parse() on retrieval.
Why It Works: JSON strings are primitive types supported by PersistentStorage.
Caveats:
- Only works for JSON-serializable data (no methods/circular references).
- Add
try-catchfor parsing errors and default values for empty storage. - Use
@StorageLinkto maintain UI reactivity.
Implementation:
// Storing
const data = [{ id: 1 }];
PersistentStorage.PersistProp('key', JSON.stringify(data));
// Retrieving
const storedData = JSON.parse(AppStorage.Get('key') || "[]");
Copy codeCopy code
Solution
- For classes without methods, convert the array data into a string using JSON.stringify() and then store it. When reading, simply parse it using JSON.parse() and use it directly. The example code is as follows:
class Student {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
PersistentStorage.persistProp('studentArr', JSON.stringify([new Student('Tom', 16), new Student('Gina', 18)]));
@Entry
@Component
struct Index {
@State studentArr: Array<Student> = [];
@StorageLink('studentArr') @Watch('onStrChange') studentArrStr: string = '[]';
onStrChange() {
this.studentArr = JSON.parse(this.studentArrStr);
}
aboutToAppear(): void {
// The Watch event is not triggered during component initialization; the array is initialized through the aboutToAppear event.
this.studentArr = JSON.parse(this.studentArrStr);
}
build() {
Column({ space: 8 }) {
ForEach(this.studentArr, (item: Student, index: number) => {
Column() {
Text(`Student Name: ${item.name}`)
.width('100%')
Text(`Student Age: ${item.age}`)
.width('100%')
}
.borderRadius(12)
.width('100%')
.backgroundColor(Color.White)
.padding(16)
}, (item: Student) => JSON.stringify(item))
}
.width('100%')
.height('100%')
.backgroundColor('#f1f3f5')
.padding(12)
}
}
- For classes with method functions, it is necessary to first convert the string into a data array, then call the class constructor to create an object using each piece of data. This way, the created object will have a prototype chain and can call the corresponding methods. The reference code is as follows:
class Student {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
selfIntroduction() {
console.log(`My name is ${this.name} and I'm ${this.age} years old.`);
}
}
PersistentStorage.persistProp('studentArr', JSON.stringify([new Student('Tom', 16), new Student('Gina', 18)]));
@Entry
@Component
struct Index {
@State studentArr: Array<Student> = [];
@StorageLink('studentArr') @Watch('onStrChange') studentArrStr: string = '[]';
onStrChange() {
const dataArr: Array<Student> = JSON.parse(this.studentArrStr);
this.studentArr = dataArr.map((item: Student) => new Student(item.name, item.age));
}
aboutToAppear(): void {
// The Watch event is not triggered during component initialization; the array is initialized through the aboutToAppear event.
const dataArr: Array<Student> = JSON.parse(this.studentArrStr);
this.studentArr = dataArr.map((item: Student) => new Student(item.name, item.age));
}
build() {
Column({ space: 8 }) {
ForEach(this.studentArr, (item: Student, index: number) => {
Column() {
// UI interface reference the code from the previous solution
Button('Get Self-introduction')
.onClick(() => {
item.selfIntroduction();
})
}
// Style reference the code from the previous solution
}, (item: Student) => JSON.stringify(item))
}
// Style reference the code from the previous solution
}
}
Verification Result
Summary
To store an array of objects as data to the hard drive using PersistentStorage, you need to convert the objects into strings using JSON.stringify() before storing them. When using the data, handle it differently based on whether the class contains methods. For data classes without methods, simply parse them using JSON.parse() and then use them. For classes with methods, you need to call the class's constructor to create an object before the object can invoke the corresponding methods; otherwise, there is a high likelihood of application crashes.


Top comments (0)