目錄
應用全局UI狀態存儲和持久化V2版本
AppStorageV2
connect
remove
keys
示例
使用限制
PersistenceV2
connect
remove
keys
save
notifyOnError
?示例
使用限制
@Type
?使用限制
應用全局UI狀態存儲和持久化V2版本
以下實例AppStorageV2、PersistenceV2和裝飾器@Type都需要搭配@ComponentV2使用。
AppStorageV2
AppStorageV2是在應用UI啟動時會被創建的單例。它的目的是為了提供應用狀態數據的中心存儲,這些狀態數據在應用級別都是可訪問的。AppStorageV2將在應用運行過程保留其數據。數據通過唯一的鍵字符串值訪問。
AppStorageV2支持應用的主線程內多個UIAbility實例間的狀態共享
connect
用于在AppStorageV2實例中創建鍵值對數據或者獲取實例中key對應的值,返回創建或獲取的值(類實例|undefinded)。返回的不為undefined情況下,該值改變,對應AppStorageV2存儲中的值也會改變。
AppStorageV2.connect<T extends object>(type: TypeConstructorWithArgs<T>, keyOrDefaultCreator?: string | StorageDefaultCreator<T>, defaultCreator?: StorageDefaultCreator<T>): T | undefined;
參數名 | 類型 | 必填 | 說明 |
---|---|---|---|
type | TypeConstructorWithArgs<T> | 是 | 指定的類型,若未指定key,則使用type的name作為key。 |
keyOrDefaultCreator | string |?StorageDefaultCreator<T> | 否 | 指定的key,或者是獲取默認值的構造器。 |
defaultCreator | StorageDefaultCreator<T> | 否 | 獲取默認值的構造器。 |
有4種形式入參:
AppStorageV2.connect(Sample)
1個參數,類名。相當于AppStorageV2.connect(Sample,"Sample")。
AppStorageV2.connect(Sample,"Sample1")
2個參數,類名+字符串。表示獲取AppStorageV2中"Sample1"對應的值,該值的類型為Sample,獲取不到返回undefined。
AppStorageV2.connect(Sample,()=>new Sample())
2個參數,類名+默認值構造器。相當于AppStorageV2.connect(Sample,"Sample",()=>new Sample)
AppStorageV2.connect(Sample,"Sample2",()=>new Sample())
3個參數,類名+字符串+默認值構造器。先獲取AppStorageV2中"Sample2"對應的值,如果獲取不到,則通過調用默認值構造器,將結果存入AppStorageV2值中,key為"Sample2"。
注意:使用時,該方法可能返回undefined,故在給@Local等裝飾器修飾的變量賦值時需要在最后加上感嘆號!,用來避過undefined的類型檢測,表示我確認不會返回undefined。
?
remove
用于刪除AppStorageV2實例中指定的鍵值對數據,返回undefined。
AppStorageV2.remove<T>(keyOrType: string | TypeConstructorWithArgs<T>): void
參數名 | 類型 | 必填 | 說明 |
---|---|---|---|
keyOrType | string | TypeConstructorWithArgs<T> | 是 | 需要刪除的key;如果指定的是type類型,刪除的key為type的name。 |
只有一種入參方式,可以傳類名或者字符串。傳類名表示直接刪除類名對應字符串后的鍵值對。?
注意:刪除AppStorageV2中不存在的key會有Warning提示The key to be deleted does not exist。
keys
AppStorageV2.keys(): Array<string>
返回AppStorageV2實例中的所有key(Array<string>)。
示例
Navigation組件跳轉頁面時,首頁不會重復渲染,返回不會重復渲染,pushPathByName會重新渲染新頁面,故下例中首頁只會渲染一次,每次跳到page2頁面都會渲染一個新的。
1.點擊Page1 p1、Page2 p2,p1數字會變動,p2不會,由于@Trace只裝飾了p1,p2的實際值增加了,但是由于UI沒刷新(在第2步中可以看出來)。
2.點擊跳轉page2,p1、p2的數字都同步過去了,由于都是在AppStorageV2實例中獲取的Sample鍵值對。
3.點擊Page2中按鈕,在AppStorageV2中創建一個新的鍵值對Sample1,當前頁面p1、p2的值會還原。
4.點擊返回,由于首頁不會刷新,這時無變化。
5.點擊all keys in AppStorage,觸發該段文字ui刷新,發現多了一個Sample1的key。
6.點擊remove key按鈕AppStorageV2中的Sample鍵值對刪除了。
7.點擊跳轉page2,發現應用直接報錯了,這是由于page2頁面重新渲染,其中下面代碼AppStorageV2.connect(Sample)返回undefined,@Local不能初始化值傳入undefined。
@Local prop: Sample = AppStorageV2.connect(Sample)!;
注意:需要在真機環境運行,在預覽環境會報錯。
Index.ets頁面
// Index.ets
import { AppStorageV2 } from '@kit.ArkUI';// 數據中心
@ObservedV2
export class Sample {@Trace p1: number = 0;p2: number = 10;
}@Entry
@ComponentV2
struct Page1 {// 在AppStorageV2中創建一個key為Sample的鍵值對(如果存在,則返回AppStorageV2中的數據),并且和prop關聯@Local prop: Sample = AppStorageV2.connect(Sample,'Sample',()=>new Sample())!;@Local prop1: String = "1"pageStack: NavPathStack = new NavPathStack();fontSize(){console.log("all keys in AppStorage:渲染了一次")return 30}build() {Navigation(this.pageStack) {Column() {Button('Go to page2').onClick(() => {this.pageStack.pushPathByName('Page2', null);})Button('Page1 connect the key Sample').onClick(() => {// 在AppStorageV2中創建一個key為Sample的鍵值對(如果存在,則返回AppStorageV2中的數據),并且和prop關聯this.prop = AppStorageV2.connect(Sample,()=>new Sample())!;})Button('Page1 remove the key Sample').onClick(() => {// 從AppStorageV2中刪除后,prop將不會再與key為Sample的值關聯AppStorageV2.remove(Sample);})Text(`Page1 p1: ${this.prop.p1}`).fontSize(30).onClick(() => {this.prop.p1++;})Text(`Page1 p2: ${this.prop.p2}`).fontSize(30).onClick(() => {// 頁面不刷新,但是p2的值改變了this.prop.p2++;})// 獲取當前AppStorageV2里面的所有keyText(`${this.prop1}all keys in AppStorage: ${AppStorageV2.keys()}`).fontSize(this.fontSize()).onClick(() => {// 頁面不刷新,但是p2的值改變了this.prop1 = this.prop1+'1'})}}}
}
Index2.ets頁面
// Page2.ets
import { AppStorageV2 } from '@kit.ArkUI';
import { Sample } from './Index';@Builder
export function Page2Builder() {Page2()
}@ComponentV2
struct Page2 {// 在AppStorageV2中創建一個key為Sample的鍵值對(如果存在,則返回AppStorageV2中的數據),并且和prop關聯@Local prop: Sample = AppStorageV2.connect(Sample)!;pathStack: NavPathStack = new NavPathStack();fontSize(){console.log("渲染了一次11")return 30}build() {NavDestination() {Column() {Button('Page2 connect the key Sample1').onClick(() => {// 在AppStorageV2中創建一個key為Sample1的鍵值對(如果存在,則返回AppStorageV2中的數據),并且和prop關聯this.prop = AppStorageV2.connect(Sample,"Sample1",()=>new Sample())!;})Text(`Page2 p1: ${this.prop.p1}`).fontSize(30).onClick(() => {this.prop.p1++;})Text(`Page2 p2: ${this.prop.p2}`).fontSize(this.fontSize()).onClick(() => {// 頁面不刷新,但是p2的值改變了;只有重新初始化才會改變this.prop.p2++;})// 獲取當前AppStorageV2里面的所有keyText(`all keys in AppStorage: ${AppStorageV2.keys()}`).fontSize(30)}}.onReady((context: NavDestinationContext) => {this.pathStack = context.pathStack;})}
}
使用Navigation組件時,需要添加配置系統路由表文件,先在module.json5中添加:"routerMap": "$profile:route_map",表示使用src/main/resources/base/profile目錄下的route_map.json文件作為路由表。故在該目錄下創建文件route_map.json。
{"routerMap": [{"name": "Page2","pageSourceFile": "src/main/ets/pages/Index2.ets","buildFunction": "Page2Builder","data": {"description" : "AppStorageV2 example"}}]
}
使用限制
1、需要配合UI使用(UI線程),不能在其他線程使用,如不支持@Sendable。
2、不支持collections.Set、collections.Map等類型。
3、不支持非buildin類型,如PixelMap、NativePointer、ArrayList等Native類型。
?
PersistenceV2
PersistenceV2是在應用UI啟動時會被創建的單例,用于儲存持久化的數據。不同于AppStorageV2它會將最新數據儲存在設備磁盤上(持久化)。這意味著,應用退出再次啟動后,依然能保存之前的數據。
支持應用的主線程內多個UIAbility實例間的狀態共享。
注意:由于將數據存儲在設備磁盤上,需要將數據進行序列化(數據轉為某種固定的格式進行存儲,例如全部轉為二進制數據)后進行存儲。
connect
remove
keys
PersistenceV2類型上繼承了AppStorageV2,在AppStorageV2的基礎上多實現了save和notifyOnError方法,所以上面3個方法使用同AppStorageV2。
save
PersistenceV2.save<T>(keyOrType: string | TypeConstructorWithArgs<T>): void;
對于與PersistenceV2關聯的@ObservedV2對象,該對象的@Trace屬性的變化,會觸發整個關聯對象的自動持久化;非@Trace屬性的變化則不會,這時需要通過該方法進行手動持久化。
save | 說明 |
---|---|
參數 | keyOrType:需要手動持久化的key;如果指定的是type類型,key為type的name。 |
返回值 | 無。 |
入參字符串或者類名。傳類名表示對類名對應字符串后的鍵值對進行持久化處理。?
notifyOnError
PersistenceV2.notifyOnError(callback: PersistenceErrorCallback | undefined): void;
將數據存入磁盤時,需要對數據進行序列化;當某個key序列化失敗時,錯誤是不可預知的;可調用該接口捕獲異常。
notifyOnError | 說明 |
---|---|
參數 | callback:當序列化或者反序列化失敗時,執行該回調;若傳入undefined,取消該回調。 |
返回值 | 無。 |
?示例
注意:需要在真機環境運行,在預覽環境會報錯。
這里示例和AppStorageV2的示例效果類似。不同在于:
1.退出應用后再次打開應用p1的值不會重置,因為使用的PersistenceV2并被@Trace修飾了,會自動持久化數據。
2.p2的值需要點擊Page1 save the key Sample按鈕后才會被持久化。這時退出后再打開p2的值會同步。
Index.ets頁面
import { Type } from '@kit.ArkUI';
import { PersistenceV2 } from '@kit.ArkUI';// 數據中心
@ObservedV2
class SampleChild {@Trace p1: number = 0;p2: number = 10;
}@ObservedV2
export class Sample {// 對于復雜對象需要@Type修飾,確保序列化成功@Type(SampleChild)@Trace f: SampleChild = new SampleChild();
}
// 接受序列化失敗的回調
PersistenceV2.notifyOnError((key: string, reason: string, msg: string) => {console.error(`error key: ${key}, reason: ${reason}, message: ${msg}`);
});@Entry
@ComponentV2
struct Page1 {// 在PersistenceV2中創建一個key為Sample的鍵值對(如果存在,則返回PersistenceV2中的數據),并且和prop關聯// 對于需要換connect對象的prop屬性,需要加@Local修飾(不建議對屬性換connect的對象)@Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;pageStack: NavPathStack = new NavPathStack();build() {Navigation(this.pageStack) {Column() {Button('Go to page2').onClick(() => {this.pageStack.pushPathByName('Page2', null);})Button('Page1 connect the key Sample').onClick(() => {// 在PersistenceV2中創建一個key為Sample的鍵值對(如果存在,則返回PersistenceV2中的數據),并且和prop關聯// 不建議對prop屬性換connect的對象this.prop = PersistenceV2.connect(Sample, 'Sample', () => new Sample())!;})Button('Page1 remove the key Sample').onClick(() => {// 從PersistenceV2中刪除后,prop將不會再與key為Sample的值關聯PersistenceV2.remove(Sample);})Button('Page1 save the key Sample').onClick(() => {// 如果處于connect狀態,持久化key為Sample的鍵值對PersistenceV2.save("Sample");})Text(`Page1 add 1 to prop.p1: ${this.prop.f.p1}`).fontSize(30).onClick(() => {this.prop.f.p1++;})Text(`Page1 add 1 to prop.p2: ${this.prop.f.p2}`).fontSize(30).onClick(() => {// 頁面不刷新,但是p2的值改變了this.prop.f.p2++;})// 獲取當前PersistenceV2里面的所有keyText(`all keys in PersistenceV2: ${PersistenceV2.keys()}`).fontSize(30)}}}
}
Index2.ets?
import { PersistenceV2 } from '@kit.ArkUI';
import { Sample } from './Index';@Builder
export function Page2Builder() {Page2()
}@ComponentV2
struct Page2 {// 在PersistenceV2中創建一個key為Sample的鍵值對(如果存在,則返回PersistenceV2中的數據),并且和prop關聯// 對于需要換connect對象的prop屬性,需要加@Local修飾(不建議對屬性換connect的對象)@Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;pathStack: NavPathStack = new NavPathStack();build() {NavDestination() {Column() {Button('Page2 connect the key Sample1').onClick(() => {// 在PersistenceV2中創建一個key為Sample1的鍵值對(如果存在,則返回PersistenceV2中的數據),并且和prop關聯// 不建議對prop屬性換connect的對象this.prop = PersistenceV2.connect(Sample, 'Sample1', () => new Sample())!;})Text(`Page2 add 1 to prop.p1: ${this.prop.f.p1}`).fontSize(30).onClick(() => {this.prop.f.p1++;})Text(`Page2 add 1 to prop.p2: ${this.prop.f.p2}`).fontSize(30).onClick(() => {// 頁面不刷新,但是p2的值改變了;只有重新初始化才會改變this.prop.f.p2++;})// 獲取當前PersistenceV2里面的所有keyText(`all keys in PersistenceV2: ${PersistenceV2.keys()}`).fontSize(30)}}.onReady((context: NavDestinationContext) => {this.pathStack = context.pathStack;})}
}
?使用Navigation組件時,需要添加配置系統路由表文件,先在module.json5中添加:"routerMap": "$profile:route_map",表示使用src/main/resources/base/profile目錄下的route_map.json文件作為路由表。故在該目錄下創建文件route_map.json。
{"routerMap": [{"name": "Page2","pageSourceFile": "src/main/ets/pages/Index2.ets","buildFunction": "Page2Builder","data": {"description" : "AppStorageV2 example"}}]
}
使用限制
1、需要配合UI使用(UI線程),不能在其他線程使用,如不支持@Sendable。
2、不支持collections.Set、collections.Map等類型。
3、不支持非buildin類型,如PixelMap、NativePointer、ArrayList等Native類型。
4、單個key支持數據大小約8k,過大會導致持久化失敗。
5、持久化的數據必須是class對象,不能是容器(如Array、Set、Map),不能是buildin的構造對象(如Date、Number)。
6、不支持循環引用的對象。
7、只有@Trace的數據改變會觸發自動持久化,如V1狀態變量、@Observed對象、普通數據的改變不會觸發持久化。
8、不宜大量持久化數據,可能會導致頁面卡頓。
@Type
在持久化數據時,為了實現序列化類時不丟失屬性的復雜類型,可以使用@Type裝飾器裝飾類屬性。
@Type裝飾器 | 說明 |
---|---|
裝飾器參數 | type:類型。 |
可裝飾的類型 | Object class以及Array、Date、Map、Set等內嵌類型。 |
class Sample {data: number = 0;
}
// Info會在PersistenceV2中使用。
//@Local prop: Info = PersistenceV2.connect(Info , () => new Info ())!;
@ObservedV2
class Info {@Type(Sample)@Trace sample: Sample = new Sample(); // 正確用法
}
?使用限制
1、只能用在@ObservedV2裝飾的類中,不能用在自定義組件中。
2、不支持collections.Set、collections.Map等類型。
3、不支持非buildin類型,如PixelMap、NativePointer、ArrayList等Native類型。
4、不支持簡單類型,如string、number、boolean等。