• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# State Management with Application-level Variables
2
3This topic covers how to manage the application status with application-level variables. For details about the APIs, see [State Management with Application-level Variables](../reference/arkui-ts/ts-state-management.md).
4
5## AppStorage
6
7The [AppStorage](../reference/arkui-ts/ts-state-management.md#appstorage) is a singleton object in an application that provides central storage for changing state attributes of an application. It is created by the UI framework when the application is started and destroyed when the application exits.
8
9The **AppStorage** contains all the state attributes that need to be accessed throughout the application. It retains all attributes and their values as long as the application remains running, and the attribute values can be accessed through unique key values.
10
11Components can synchronize the application state data with the **AppStorage** through decorators. The application service logic can also be implemented by accessing the **AppStorage** through APIs.
12
13The selection state attribute of the **AppStorage** can be synchronized with different data sources or data sinks. These data sources and data sinks can be local or remote devices and provide different functions, such as data persistence. Such data sources and data sinks can be implemented independently of the UI in the service logic.
14
15By default, the attributes in the **AppStorage** are mutable. If needed, **AppStorage** can also use immutable (read-only) attributes.
16
17> **NOTE**
18>
19> [Worker](../reference/apis/js-apis-worker.md) can interact with the main thread only through [postMessage](../reference/apis/js-apis-worker.md#postmessage).
20
21### @StorageLink Decorator
22
23Two-way data binding can be established between components and the **AppStorage** through state variables decorated by **@StorageLink(*key*)**. Wherein, **key** is the attribute key value in the **AppStorage**. When a component containing the **@StorageLink** decorated variable is created, the variable is initialized using the value in the **AppStorage**. Changes made to this variable in the component will be first synchronized to the **AppStorage**, and then to other bound instances, such as **PersistentStorage** or other bound UI components.
24
25### @StorageProp Decorator
26
27One-way data binding can be established between components and the **AppStorage** through state variables decorated by **@StorageProp(*key*)**. Wherein, **key** is the attribute key value in the **AppStorage**. When a component containing the **@StorageProp** decorated variable is created, the variable is initialized using the value in the **AppStorage**. Changes made to the value in the **AppStorage** will cause the bound UI component to update the state.
28
29### Example
30
31Each time the user clicks the **Count** button, the value of **this.varA** will increase by 1. This variable is synchronized with **varA** in the **AppStorage**. Each time the user clicks the language button, the value of **languageCode** in the **AppStorage** will be changed, and the change is synchronized to the **this.languageCode** variable.
32
33```ts
34// xxx.ets
35@Entry
36@Component
37struct ComponentA {
38  @StorageLink('varA') varA: number = 2
39  @StorageProp('languageCode') languageCode: string = 'en'
40  private label: string = 'count'
41
42  aboutToAppear() {
43    this.label = (this.languageCode === 'en') ? 'Number' : 'Count'
44  }
45
46  build() {
47    Column() {
48      Row({ space: 20 }) {
49        Button(`${this.label}: ${this.varA}`)
50          .onClick(() => {
51            AppStorage.Set<number>('varA', AppStorage.Get<number>('varA') + 1)
52          })
53        Button(`language: ${this.languageCode}`)
54          .onClick(() => {
55            if (AppStorage.Get<string>('languageCode') === 'zh') {
56              AppStorage.Set<string>('languageCode', 'en')
57            } else {
58              AppStorage.Set<string>('languageCode', 'zh')
59            }
60            this.label = (this.languageCode === 'en') ? 'Number' : 'Count'
61          })
62      }
63      .margin({ top: 50, bottom: 50 })
64
65      Row() {
66        Button (`Change @StorageLink decorated variable: ${this.varA}`).height(40).fontSize(14)
67          .onClick(() => {
68            this.varA++
69          })
70      }
71    }.width('100%')
72  }
73}
74```
75
76![appstorage](figures/appstorage.gif)
77
78## LocalStorage
79
80> **NOTE**
81>
82> This API is supported since API version 9. Updates will be marked with a superscript to indicate their earliest API version.
83
84The **LocalStorage** is a storage unit in an application. Its lifecycle follows its associated ability. In the stage model, the **LocalStorage** provides global data isolation between abilities and applies to where a data sharing scope smaller than that provided by the **AppStorage** is required. The **LocalStorage** also provides storage for application-wide mutable and immutable state attributes, which are used for building part of the application UI, such as an ability UI. The **LocalStorage** resolves the data interference between the application and the abilities and, in multi-instance scenarios, data interference between different **Ability** instances under the same **Ability** class. In distributed migration scenarios, **Ability**, as the minimum unit for the system to schedule applications, allows for easier component data migration when working with the **LocalStorage**.
85
86At the application layer, multiple **LocalStorage** instances can be created for an application, each corresponding to an ability of the application.
87
88An application can have multiple abilities. At most one **LocalStorage** instance can be allocated to the components in an ability. In addition, all components in the ability inherit access to the objects stored in the **LocalStorage** instance.
89
90A component can access a maximum of one **LocalStorage** instance, and one **LocalStorage** instance can be assigned to multiple components.
91
92### @LocalStorageLink Decorator
93
94Two-way data binding can be established between a component and the **LocalStorage** through the component's state variable decorated by **@LocalStorageLink(*key*)**. Wherein, **key** is the attribute key value in the **LocalStorage**. When a component that contains a **@LocalStorageLink** decorated state variable is created, the state variable is initialized with the initial value in the **LocalStorage**. If no initial value is assigned in the **LocalStorage**, the state variable will use the value defined by **@LocalStorageLink**. Changes made to the **@LocalStorageLink** decorated variable in a component will be first synchronized to the **LocalStorage**, and then to other bound UI components under the same ability.
95
96### @LocalStorageProp Decorator
97
98One-way data binding can be established between a component and the **LocalStorage** through the component's state variable decorated by **@LocalStorageProp(*key*)**. Wherein, **key** is the attribute key value in the **LocalStorage**. When a component that contains a **@LocalStorageProp** decorated state variable is created, the state variable is initialized with the initial value in the **LocalStorage**. Changes made to the value in the **LocalStorage** will cause all UI components under the current ability to update the state.
99
100> **NOTE**
101>
102> If a **LocalStorage** instance does not have an initial value assigned when being created, it can use the initial value defined by **@LocalStorageLink** or **@LocalStorageProp** in the component.
103
104### Example 1: Creating a LocalStorage Instance in an Ability
105
106The **LocalStorage** is loaded through the **loadContent** API. For details, see [loadContent](../reference/apis/js-apis-window.md#loadcontent9-1).
107
108```ts
109// MainAbility.ts
110import Ability from '@ohos.application.Ability'
111
112export default class MainAbility extends Ability {
113    storage: LocalStorage
114
115    onCreate() {
116        this.storage = new LocalStorage()
117        this.storage.setOrCreate('storageSimpleProp', 121)
118        console.info('[Demo MainAbility onCreate]')
119    }
120
121    onDestroy() {
122        console.info('[Demo MainAbility onDestroy]')
123    }
124
125    onWindowStageCreate(windowStage) {
126        // storage is passed to the loadContent API as a parameter.
127        windowStage.loadContent('pages/Index', this.storage)
128    }
129
130    onWindowStageDestroy() {
131        console.info('[Demo] MainAbility onWindowStageDestroy')
132    }
133
134    onForeground() {
135        console.info('[Demo] MainAbility onForeground')
136    }
137
138    onBackground() {
139        console.info('[Demo] MainAbility onBackground')
140    }
141}
142```
143
144The **@Component** decorated component obtains data.
145
146```ts
147// Index.ets
148let storage = LocalStorage.GetShared()
149
150@Entry(storage)
151@Component
152struct LocalStorageComponent {
153  @LocalStorageLink('storageSimpleProp') simpleVarName: number = 0
154
155  build() {
156    Column() {
157      Button(`LocalStorageLink: ${this.simpleVarName.toString()}`)
158        .margin(20)
159        .onClick(() => {
160          this.simpleVarName += 1
161        })
162      Text(JSON.stringify(this.simpleVarName))
163        .fontSize(50)
164      LocalStorageComponentProp()
165    }.width('100%')
166  }
167}
168
169@Component
170struct LocalStorageComponentProp {
171  @LocalStorageProp('storageSimpleProp') simpleVarName: number = 0
172
173  build() {
174    Column() {
175      Button(`LocalStorageProp: ${this.simpleVarName.toString()}`)
176        .margin(20)
177        .onClick(() => {
178          this.simpleVarName += 1
179        })
180      Text(JSON.stringify(this.simpleVarName))
181        .fontSize(50)
182    }.width('100%')
183  }
184}
185```
186
187![appstorage1](figures/appstorage1.gif)
188
189### Example 2: Defining LocalStorage on the Entry Page
190
191```ts
192// xxx.ets
193let storage = new LocalStorage({ "PropA": 47 })
194
195@Entry(storage)
196@Component
197struct ComA {
198  @LocalStorageLink("PropA") storageLink: number = 1
199
200  build() {
201    Column() {
202      Text(`Parent from LocalStorage ${this.storageLink}`)
203        .fontSize(18)
204        .margin(20)
205        .onClick(() => this.storageLink += 1)
206      Child()
207    }
208  }
209}
210
211@Component
212struct Child {
213  @LocalStorageLink("PropA") storageLink: number = 1
214
215  build() {
216    Text(`Child from LocalStorage ${this.storageLink}`)
217      .fontSize(18)
218      .margin(20)
219      .onClick(() => this.storageLink += 1)
220  }
221}
222```
223
224![appstorage2](figures/appstorage2.gif)
225
226## PersistentStorage
227
228[PersistentStorage](../reference/arkui-ts/ts-state-management.md#persistentstorage) provides a set of static methods for managing persistent data of applications. Persistent data with specific tags can be linked to the **AppStorage**, and then the persistent data can be accessed through the **AppStorage** APIs. Alternatively, the **@StorageLink** decorator can be used to access the variable that matches the specific key.
229
230> **NOTE**
231>
232> - When using the **PersistProp** API in **PersistentStorage**, ensure that the input key exists in the **AppStorage**.
233> - The **DeleteProp** API in **PersistentStorage** takes effect only for the data that has been linked during the current application startup.
234
235```ts
236// xxx.ets
237PersistentStorage.PersistProp('highScore', '0')
238
239@Entry
240@Component
241struct PersistentComponent {
242  @StorageLink('highScore') highScore: string = '0'
243  @State currentScore: number = 0
244
245  build() {
246    Column() {
247      if (this.currentScore === Number(this.highScore)) {
248        Text(`new highScore : ${this.highScore}`).fontSize(18)
249      }
250      Button(`goal!, currentScore : ${this.currentScore}`)
251        .margin(20)
252        .onClick(() => {
253          this.currentScore++
254          if (this.currentScore > Number(this.highScore)) {
255            this.highScore = this.currentScore.toString()
256          }
257        })
258    }.width('100%')
259  }
260}
261```
262
263![appstorage3](figures/appstorage3.gif)
264
265## Environment
266
267[Environment](../reference/arkui-ts/ts-state-management.md#environment) is a singleton object created by the framework when the application is started. It provides the **AppStorage** with an array of environment state attributes required by the application. These attributes, such as the system language and color mode, describe the device environment where the application runs. **Environment** and its attributes are immutable, and all attribute values are of simple types. The following example shows how to obtain whether accessibility is enabled from **Environment**:
268
269```ts
270Environment.EnvProp('accessibilityEnabled', 'default')
271var enable = AppStorage.Get('accessibilityEnabled')
272```
273
274**accessibilityEnabled** is the default system variable identifier provided by **Environment**. You need to bind the corresponding system attribute to the **AppStorage**. Then, you can use the methods or decorators in the **AppStorage** to access the corresponding system attribute data.
275