鸿蒙ACE-V2状态分析@PersistenceV2

132 阅读2分钟

PersistenceV2: 持久化储存UI状态

developer.huawei.com/consumer/cn…

PersistenceV2是在应用UI启动时会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。数据通过唯一的键字符串值访问。不同于AppStorageV2,PersistenceV2还将最新数据储存在设备磁盘上(持久化)。这意味着,应用退出再次启动后,依然能保存选定的结果

转换前

/**
 *
 * PersistenceV2Cmp.ets
 * Created by unravel on 2024/8/2
 * @abstract
 */
import { router, PersistenceV2 } from '@kit.ArkUI';
import { Type } 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}`);
});

@ComponentV2
export struct PersistenceV2Cmp {
  // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联
  // 对于需要换connect对象的prop属性,需要加@Local修饰(不建议对属性换connect的对象)
  @Local prop: Sample = PersistenceV2.connect(Sample, () => new Sample())!;

  build() {
    Column() {
      Button('Go to page2')
        .onClick(() => {
          router.pushUrl({
            url: 'pages/Page2'
          })
        })

      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里面的所有key
      Text(`all keys in PersistenceV2: ${PersistenceV2.keys()}`)
        .fontSize(30)
    }
  }
}

转换后

if (!("finalizeConstruction" in ViewPU.prototype)) {
    Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { });
}
import router from "@ohos:router";
import { PersistenceV2 } from "@ohos:arkui.StateManagement";
import { Type } from "@ohos:arkui.StateManagement";
// 数据中心
@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}`);
});
export class PersistenceV2Cmp extends ViewV2 {
    constructor(parent, params, __localStorage, elmtId = -1, paramsLambda, extraInfo) {
        super(parent, elmtId, extraInfo);
        this.prop = PersistenceV2.connect(Sample, () => new Sample())!;
        this.finalizeConstruction();
    }
    // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联
    // 对于需要换connect对象的prop属性,需要加@Local修饰(不建议对属性换connect的对象)
    @Local
    prop: Sample;
    initialRender() {
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Column.create();
        }, Column);
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Button.createWithLabel('Go to page2');
            Button.onClick(() => {
                router.pushUrl({
                    url: 'pages/Page2'
                });
            });
        }, Button);
        Button.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Button.createWithLabel('Page1 connect the key Sample');
            Button.onClick(() => {
                // 在PersistenceV2中创建一个key为Sample的键值对(如果存在,则返回PersistenceV2中的数据),并且和prop关联
                // 不建议对prop属性换connect的对象
                this.prop = PersistenceV2.connect(Sample, 'Sample', () => new Sample())!;
            });
        }, Button);
        Button.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Button.createWithLabel('Page1 remove the key Sample');
            Button.onClick(() => {
                // 从PersistenceV2中删除后,prop将不会再与key为Sample的值关联
                PersistenceV2.remove(Sample);
            });
        }, Button);
        Button.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Button.createWithLabel('Page1 save the key Sample');
            Button.onClick(() => {
                // 如果处于connect状态,持久化key为Sample的键值对
                PersistenceV2.save(Sample);
            });
        }, Button);
        Button.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create(`Page1 add 1 to prop.p1: ${this.prop.f.p1}`);
            Text.fontSize(30);
            Text.onClick(() => {
                this.prop.f.p1++;
            });
        }, Text);
        Text.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            Text.create(`Page1 add 1 to prop.p2: ${this.prop.f.p2}`);
            Text.fontSize(30);
            Text.onClick(() => {
                // 页面不刷新,但是p2的值改变了
                this.prop.f.p2++;
            });
        }, Text);
        Text.pop();
        this.observeComponentCreation2((elmtId, isInitialRender) => {
            // 获取当前PersistenceV2里面的所有key
            Text.create(`all keys in PersistenceV2: ${PersistenceV2.keys()}`);
            // 获取当前PersistenceV2里面的所有key
            Text.fontSize(30);
        }, Text);
        // 获取当前PersistenceV2里面的所有key
        Text.pop();
        Column.pop();
    }
    rerender() {
        this.updateDirtyElements();
    }
}

AppStorageV2 类

底层的实际处理类是PersistenceV2Impl

PersistenceV2.persistenceV2Impl_ = PersistenceV2Impl.instance();

image.png

class PersistenceV2Impl extends StorageHelper

image.png

public connect(type: TypeConstructorWithArgs, keyOrDefaultCreator?: string | StorageDefaultCreator, defaultCreator?: StorageDefaultCreator): T | undefined

image.png

PersistenceV2和AppStorageV2一样

对于内存缓存,存储的是一个对象的引用,然后App内多个页面之所以能够同步是因为他们访问的是同一个对象

对于磁盘缓存,存储的是序列化的json字符串

PersistenceV2本身不能观察数据的变化,实际驱动UI刷新的动作还需要数据自身来完成,即对应的class必须使用ObservedV2和Trace装饰