官网中叫 Persisting State ,状态持久化。

使用插件时,总会需要保存插件的某些数据,再重启IntelliJ工具时,能接着使用。对于插件数据,IntelliJ分成两类:

  • 组件状态:某个组件显示的数据
  • 私有数据:各种密码之类的敏感数据

1 处理组件状态

对于 组件服务 的内部状态,IntelliJ提供了两种方式:

  • PropertiesComponent:这是一个服务,用来存储临时的、不经常变动的值
  • PersistentStateComponent:这是一个普通的Java接口,通过实现这个接口,来处理复杂的数值存储

1.1 PropertiesComponent

这个 Service 的使用非常简单,可以用在 ApplicationProject 级别,存储一些临时的、不经常变动的数据,如下:

  1. // 获取Application级别数据
  2. PropertiesComponent appProp = PropertiesComponent.getInstance();
  3. // 获取Project级别数据
  4. PropertiesComponent proProp = PropertiesComponent.getInstance(Project);
  5. // 使用方式
  6. appProp.setValue("key", "value");
  7. String value = appProp.getValue("key");

使用起来,确实很容易

1.2 PersistentStateComponent

1.2.1 基础使用

插件中,总会用到一些复杂数据,比如:Map,这时,就会用到 PersistentStateComponent 这个接口,用起来也很简单,通常,我们只需:

  • 定义一个 Service
  • 实现 PersistentStateComponent 这个接口
  • 使用 @com.intellij.openapi.components.State 这个注解标明存储位置

就可以了,如下:
单独状态类
使用Service字段
需要注意的地方:

  • 这种方式,只会序列化 public 字段,如果要处理 private 型字段,需要用到注解
  • 可以使用 @com.intellij.util.xmlb.annotations.Transient 注解来排除不需要序列化的字段
  • 状态类必须有一个 默认的构造函数 ,再第一次加载时,要返回一个默认的状态,不能返回null
  • 状态类应该实现 equal 方法,如果没实现,会通过比较其中的 public 字段来确认是否相等

这种方式支持的数据类型有:

  • number,数字类型:int或Integer等等
  • booleans,布尔类型:true或false
  • string,字符串型
  • collections,集合类型:如List
  • maps,映射或叫字典,如:HashMap
  • enums,枚举

    1.2.2 转换器

    有时需要一些类型的转换,比如 时间字符串 转换为 LocalDateTime ,此时可以使用:

  • com.intellij.util.xmlb.Converter 类,需要继承它

  • @com.intellij.util.xmlb.annotations.OptionTag@com.intellij.util.xmlb.annotations.Attribute 类,标明使用地方

如下:
定义

  1. class LocalDateTimeConverter extends Converter<LocalDateTime> {
  2. public LocalDateTime fromString(String value) {
  3. final long epochMilli = Long.parseLong(value);
  4. final ZoneId zoneId = ZoneId.systemDefault();
  5. return Instant.ofEpochMilli(epochMilli).atZone(zoneId).toLocalDateTime();
  6. }
  7. public String toString(LocalDateTime value) {
  8. final ZoneId zoneId = ZoneId.systemDefault();
  9. final long toEpochMilli = value.atZone(zoneId).toInstant().toEpochMilli();
  10. return Long.toString(toEpochMilli);
  11. }
  12. }

使用

  1. class State {
  2. @OptionTag(converter = LocalDateTimeConverter.class)
  3. public LocalDateTime dateTime;
  4. }

1.2.3 声明存储位置

通过使用 @com.intellij.openapi.components.State 这个注解来指定数据的存储位置,需要指定以下几个值:

  • name,必须的,指定 State 的名称,也是存储的 xml 的根节点
  • storages,非必须的,指定了存储文件的位置,可以包含多个存储位置
  • reloadable,非必须的,如果设置成false,当存储 xml 文件在外部被修改时,而且 State 也被改变时,要重启整个项目或应用

对于上面的 storages 属性,它包含了 @Storage 属性,通常有以下用法:

  • @Storage("yourName.xml") ,直接指定文件的存储位置
  • @Storage(StoragePathMacros.WORKSPACE_FILE) ,存储到工作空间

其他的注解:

注解 说明

参考

https://jetbrains.org/intellij/sdk/docs/basics/persisting_state_of_components.html