原文链接:
http://www.jetbrains.org/intellij/sdk/docs/basics/persisting_state_of_components.html
IntelliJ平台 提供了一个允许组件或服务在IDE重启后持久化状态的API。你可以使用简单的API来持久化一些值,或使用PersistentStateComponent接口来持久化复杂组件的状态。
简单不可漫游(non-roamable)的状态使用PropertiesComponent
如果你的插件只是想持久化一些简单的值,最简单的方法就是使用com.intellij.ide.util.PropertiesComponent
服务。 它可以同时保存应用级和项目级数据(保存在workspace文件)。PropertiesComponent
中漫游(Roaming)时无法使用的,所以它只适合于临时的,不可漫游的属性。
使用PropertiesComponent.getInstance()
方法保存应用级数据,PropertiesComponent.getInstance(Project)
方法保存项目级数据。
因为所有插件共享相同的命名空间,强烈推荐使用前缀(如你对插件ID)。
使用PersistentStateComponent
com.intellij.openapi.components.PersistentStateComponent
接口为你提供了最大的灵活性来定义要持久化的值以及它们的格式和存储位置。要使用它,你需要是你的服务或组件实现PersistentStateComponent
接口,定义状态类并使用@com.intellij.openapi.components.State
注解指定存储位置。
注意:扩展实例不能通过实现
PersistentStateComponent
来保持它们的状态。 如果你的扩展需要持久化状态,则需要定义一个单独的服务来负责管理状态。
实现PersistentStateComponent接口
PersistentStateComponent
的实现需要使用状态类的类型进行参数化。 状态类可以是单独的JavaBean类,也可以是实现PersistentStateComponent
本身的类。
前一种方案,状态类的实例通常作为一个字段存储在PersistentStateComponent
类中:
class MyService implements PersistentStateComponent {
static class State {
public String value;
}
State myState;
public State getState() {
return myState;
}
public void loadState(State state) {
myState = state;
}
}
后一种方案,你可以使用以下方式实现getState()
和loadState()
方法:
class MyService implements PersistentStateComponent {
public String stateValue;
public MyService getState() {
return this;
}
public void loadState(MyService state) {
XmlSerializerUtil.copyBean(state, this);
}
}
实现状态类
PersistentStateComponent
的实现是序列化公共字段,注解的私有字段和bean属性为XML格式。以下类型的值可以被持久化:
- numbers (基本类型
int
或装箱类型Integer
) - booleans
- strings
- collections
- maps
- enums
为了在序列化时排除一个公共字段或bean属性,你可以对此字段或属性使用@com.intellij.util.xmlb.annotations.Transient
注解。
注意:状态类必须有默认构造方法。它应该返回组件的默认状态(如果XML文件中没有任何内容,则使用该状态)。
状态类应该有一个equals
方法,如果没有,状态对象将通过字段进行比较。如果你使用Kotlin,使用Data.
定义存储位置
为了指定持久化值保存的位置,你需要向PersistentStateComponent
类添加一个@State
注解。它有以下字段:
-
name
(必须) — 指定状态的名称(XML中的根标签名); -
storages
— 一个或多个@com.intellij.openapi.components.Storage
注解指定存储位置。对于项目级的值是可选的 — 这种情况状态会保存在标准项目文件中; -
reloadable
(可选) — 如果设置为false
,当XML文件被外部更改或状态更改时,项目或应用需要重新加载。
指定@Storage
注解最简单的方式(从IntelliJ IDEA 16起,之前版本请查看本文档的旧版本):
@Storage("yourName.xml")
如果组件时项目级的 — 标准.ipr
项目文件会被自动使用,你不必指定这个值;@Storage(StoragePathMacros.WORKSPACE_FILE)
值保存在工作空间文件。
通过为value
参数(IntelliJ IDEA 16之前为file
)指定不同的值,可以使状态保存在其他文件中。 对于应用级组件强烈建议使用自定义文件,不推荐使用other.xml
。
@Storage
注解的roamingType
参数指定可漫游类型,需要启用Settings Repository插件。
自定义持久化值的XML格式
请使用注解参数保证先后兼容性。
如果你想使用默认的bean序列化但需要自定义XML中的存储格式(例如为了兼容之前版本的插件或外部定义的XML格式),你可以使用@Tag
、@Attribute
、@Property
、@MapAnnotation
和@AbstractCollection
注解。
你可以查看源代码(com.intellij.util.xmlb
包)获取更多这些注解的信息。
如果你需要序列化的状态不能清楚地映射为一个JavaBean,比可以使用org.jdom.Element
作为状态类。在这种情况下,你可以使用getState()
方法构建任意结构的XML元素,然后它们将直接保存到状态XML文件中。在loadState()
方法中,你可以使用任何自定义逻辑反序列化JDOM元素树。但是这种方式并不推荐应该尽量避免。
组件生命周期中的持久化
loadState()
方法在组件创建后(只有组件有一些非默认状态时)或保存状态的XML被外部更改(例如,项目文件被版本控制系统更改)后被调用。后一种情况,组件会根据改变的状态更新UI和其他相关组件。
getState()
方法在每次设置保存(例如关闭IDE)时被调用。如果getState()
返回的状态与默认状态(通过状态类的默认构造方法)相等,不会在XML中保存状态。否则返回的状态将被序列化后保存。
早期API (JDOMExternalizable)
早期的IDEA组件使用JDOMExternalizable
接口持久化状态。它使用readExternal()
方法从JDOM元素中读取状态,使用writeExternal()
方法写入状态。
JDOMExternalizable
可以实现手动保存状态到子元素或属性中,或使用DefaultJDOMExternalizer
类自动保存所有公共字段。
当组件实现了JDOMExternalizable
接口,组件会将它们的状态保存到以下文件:
- 项目级组件的状态保存在项目(
.ipr
)文件。但是如果plugin.xml
文件的workspace选项设置为true
,那么组件的状态就会保存在工作空间(.iws
)文件; - 模块级组件的状态保存在模块(
.iml
)文件。