Persisting State of Components

IntelliJ IDEA组件的持久化状态

IntelliJ IDEA提供了允许组件或服务在IntelliJ IDEA每次重启之间保持它们的状态的API。你可以使用一个简单的API保存少量值,也可以使用PersistentStateComponent接口为更复杂的组件的状态进行持久化。

使用PropertiesComponent进行简单的持久化

如果你的插件需要持久化的只是少量简单的值,最容易实现的方式是使用com.intellij.ide.util.PropertiesComponent服务。它即可以在保存application级的值,也可以保存project水平的值(保存在workspace文件中)。

使用PropertiesComponent.getInstance()方法来保存application水平的值,使用PropertiesComponent.getInstance(Project)方法来保存project水平的值。

因为所有的插件共用同一命名空间,因此高度推荐为你的Key名称增加前缀(比如你的插件ID)。

使用PersistentStateComponent

com.intellij.openapi.components.PersistentStateComponent为你提供了定义要持久化的值、它们的格式、存储位置等大多数的灵活性。要使用它,你需要标记组件或服务实现PersistentStateComponent接口、定义状态类并使用@com.intellij.openapi.components.State标注指定存储位置。

注意(仅)通过实现PersistentStateComponent,扩展的实例不能保存它们的状态。如果你的扩展需要有持久化状态,你需要定义一个单独的服务来负责管理那个状态。(附原文:Note that instances of extensions cannot persist their state by implementing PersistentStateComponent. If your extension needs to have persistent state, you need to
define a separate service responsible for managing that state.我实际写的代码里并没有实现一个单独的服务,只是把PersistentStateComponent实现类注册成了application component,持久化也工作了……原文是要表达什么意思不太明白,欢迎回复讨论。)

实现PersistentStateComponent接口

PersistentStateComponent实现类需要通过状态类类型参数化。状态类可以是独立的JavaBean类,也可以是实现PersistentStateComponent的类本身。

前一种情况,通常状态类的实例作为PersistentStateComponent实现类的一个field(在内存中)存储:

class MyService implements PersistentStateComponent<MyService.State> {
    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<MyService> {
    public String stateValue;

    public MyService getState() {
        return this;
    }

    public void loadState(MyService state) {
        XmlSerializerUtil.copyBean(state, this);
    }
}

实现State类

PersistentStateComponent实现类通过将public field和bean的属性序列化为XML格式来工作。如下类型的值可以被持久化:

  • 数字(包括基础类型如int和封装类型如Integer);
  • 布尔值;
  • 字符串;
  • 集合;
  • 映射;
  • 枚举。

要排除一个public field或bean属性的序列化,你可以使用@com.intellij.util.xmlb.annotations.Transient标注对field或getter进行注释。

注意状态类必须有一个默认构造器。它应返回组件的默认状态(将用于还没有任何XML持久数据的情况)。

定义存储位置

为了准确的指定持久值要存储的位置,你需要为PersistentStateComponent实现类增加一个@State注释。它需要如下字段:

  • name(必需) - 指定状态的名称(XML中的根标记名称)
  • 一个或更多@com.intellij.openapi.components.Storage注释(必需) - 为.ipr和基于文件夹的project指定存储位置。
  • roamingType(com.intellij.openapi.components.RoamingType,可选) - 指定当IDEA Server插件启用时,在不同IDEA安装之前是否启用状态同步。(不了解IDEA Server plugin,附原文:specifies whether the state is synchronized between different IDEA installations when the IDEA Server plugin is used)
  • reloadable(可选) - 如果设为否,当XML文件被外部修改或状态变更时,需要project完全重新加载。

最简单地指定@Storage注释的方式如下:

  • @Storage(id=”other”, file = StoragePathMacros.APP_CONFIG + “/other.xml”) 用于application水平的值
  • @Storage(id=”other”, file = StoragePathMacros.PROJECT_FILE) 用于值保存在project文件(对于基于.ipr文件的project)中的情况
  • @Storage(id = “dir”, file = StoragePathMacros.PROJECT_CONFIG_DIR + “/other.xml”, scheme = StorageScheme.DIRECTORY_BASED)}) 用于值保存在project文件夹(对于基于文件夹的project)中的情况
  • @Storage(id=”other”, file = StoragePathMacros.WORKSPACE_FILE) 用于值保存在workspace文件中的情况

@Storage注释的id参数可以用来按指定的格式排除指定field的序列化(译者未试验)。如果你不需要排除任何内容,你可以指定id为任意字符串值。

通过为file参数指定不同的值,你可以使状态持久化不同的文件中。

当使用基于文件夹的项目格式时,如果你需要指定值保存的位置,你需要增加第二个@Storage注释,其包含一个值被设为StorageScheme.DIRECTORY_BASED的scheme参数,例如:

@State(
    name = "AntConfiguration",
    storages = {
        @Storage(id = "default", file = StoragePathMacros.PROJECT_FILE),
        @Storage(id = "dir", file = StoragePathMacros.PROJECT_CONFIG_DIR + "/ant.xml", scheme = StorageScheme.DIRECTORY_BASED)
    }
)

自定义持久化值的XML格式

如果你要持久化状态并不简洁的匹配一个JavaBean,你可以使用org.jdom.Element作为状态类。在这种情况下,你可以使用getState()方法来构建一个具有任意结构的会被直接保存到状态XML文件中的XML元素。在loadState()方法中,你可以使用自定义的逻辑对JDOM元素树进行反向序列化。

如果你想使用默认的bean序列化但又需要自定义XML存储格式(例如,适应你的插件的旧版本或外部定义的XML格式),你可以使用@Tag、@Attribute、@Property、@MapAnnotation、@AbstractCollection注释。你可以查阅源代码(com.intellij.util.xmlb包下)来获取更多这些注释的意义的信息。

持久化组件的生命周期

当组件被创建后或保持持久化状态的XML文件被外部修改(如project文件被版本控制系统更新)时,loadState()方法被调用(仅当组件存在无默认值的持久化状态时)。在后一种情形下,组件要负责更新UI和其他依据此被修改状态的相关组件。

getState()方法在每次设置保存时(如当窗口失去焦点或IDE关闭时)调用。 如果getState()方法返回的状态与默认状态(由使用默认构造器创建的状态类获取)相等,那么什么都不会持久化到XML里。否则,返回的状态会被序列化为XML并存储。

经典API(JDOMExternalizable)

旧版的IDEA组件使用JDOMExternalizable接口持久化状态。它使用readExternal()方法从JDOM元素中读取状态,使用writeExternal()方法向其写入状态。JDOMExternalizable实现类可以手动地在属性和子元素中存储状态,使用DefaultJDOMExternalizer类来自动地存储所有的public field值。

当组件的类实现JDOMExternalizable接口时,组件将其状态保存到以下文件:

  • Project组件保存其状态到project文件(.ipr)。然而,如果plugin.xml文件中workspace选项值为true,组件会将其配置保存到workspace文件(.iws)。
  • Module组件保存其状态到module文件(.iml)里。
时间: 2024-11-18 06:39:59

Persisting State of Components的相关文章

[BTS] Exception occurred when persisting state to the database

Uncaught exception (see the 'inner exception' below) has suspended an instance of service 'JD.EAI.POCheck(e8eb59a4-87f2-1933-5d4f-3bef0d073ae9)'. The service instance will remain suspended until administratively resumed or terminated. If resumed the

addddd

Virtual Files A virtual file com.intellij.openapi.vfs.VirtualFile is the IntelliJ Platform's representation of a file in a file system (VFS). Most commonly, a virtual file is a file in your local file system. However, the IntelliJ Platform supports m

插件api

public class TextBoxes extends AnAction { // If you register the action from Java code, this constructor is used to set the menu item name // (optionally, you can specify the menu description and an icon to display next to the menu item). // You can

IntelliJ IDEA插件结构

IntelliJ IDEA插件结构 插件是扩展IDEA功能的唯一途径.一款插件使用IDEA或其他插件暴露的API实现它的功能.这篇文章关注插件系统的结构和插件的生命周期.文章中不会指出任何可能被插件使用的其他API接口. 文章中包含了以下主题: 插件内容 插件类加载器 插件组件 插件扩展和扩展点 插件交互(Action) 插件服务 插件配置文件 插件内容 有3种方式组织插件内容: 1.由插件文件夹内的一个.jar文件构成一个插件.这个压缩包内应该包含配置文件(META-INF/plugin.xm

intellij 插件结构(文件结构以及概念层面上的结构)

1.插件内的文件 2.插件类加载器 3.插件组件(component) 4.插件的扩展以及扩展点(Extensions.Extension Points) 5.插件的Action 6.插件的Service 7.插件配置文件结构 8.插件依赖 插件内的文件 有两种方式组织你的插件目录内的文件. 1.插件相关的 jar 文件放在插件根目录下 2.jar 文件放在 lib 文件夹下 如下:实际上,大部分都是插件目录下放个lib文件夹,把插件放到 lib 下. 我们通过 idea 的 build 菜单的

OPENVPN搭建与配置

Content-type: text/html; charset=UTF-8 openvpn Section: Maintenance Commands (8)Updated: 17 November 2008Index Return to Main Contents NAME openvpn - secure IP tunnel daemon. SYNOPSIS openvpn [ options ... ] INTRODUCTION OpenVPN is an open source VPN

InputMethodManagerService处理输入法——监听APK变动

android\frameworks\base\services\java\com\android\server\InputMethodManagerService.java public InputMethodManagerService(Context context, WindowManagerService windowManager) { ....... //构建IME通知栏显示信息 mImeSwitcherNotification = new Notification(); mIme

The Eclipse runtime options

Version 3.6 - Last revised August 5, 2009 The Eclipse platform is highly configurable. Configuration input takes the form of command line arguments and System property settings. In many cases the command line arguments are simply short cuts for setti

Overview of the Oppia codebase(Oppia代码库总览)

Oppia is built with Google App Engine. Its backend is written in Python, and its frontend is written using AngularJS. Oppia是基于Google App Engine开发建设的.它的后台是用Python编写,前端是用AngularJS编写. The core核心 Most of Oppia's functionality is in the core/ directory, w