当用户关闭工作台时就会触发工作空间保存处理,而在其它时间平台会定期触发工作空间保存处理。插件可以参与工作空间保存处理,因此,每当保存工作空间的余下持久数据时,就会将关键的插件数据保存到磁盘中。
还可以使用工作空间保存处理来跟踪在激活插件之间所发生的更改。
要参与工作空间保存,必须将保存参与者添加到工作空间中。这通常是在插件启动方法中完成的。还可以从中读取在上次关闭插件时可能保存的任何状态。
让我们看一下将演示保存进程的简单插件。
package com.example.saveparticipant;
import org.eclipse.core.runtime.*;
import org.eclipse.core.resources.*;
import java.io.File;
import java.util.*;
public class MyPlugin extends Plugin {
private static MyPlugin plugin;
public MyPlugin(IPluginDescriptor descriptor) {
super(descriptor);
plugin = this;
}
public static MyPlugin getDefault() {
return plugin;
}
protected void readStateFrom(File target) {
}
public void startup() throws CoreException {
super.startup();
ISaveParticipant saveParticipant = new MyWorkspaceSaveParticipant();
ISavedState lastState =
ResourcesPlugin.getWorkspace().addSaveParticipant(this, saveParticipant);
if (lastState == null)
return;
IPath location = lastState.lookup(new Path("save"));
if (location == null)
return;
// the plugin instance should read any important state from the file.
File f = getStateLocation().append(location).toFile();
readStateFrom(f);
}
protected void writeImportantState(File target) {
}
}
ISaveParticipant 定义用于工作空间保存参与者的协议。此接口的实现哭可以提供保存进程的不同阶段的行为。让我们看一下各个阶段,以及类 WorkspaceSaveParticipant 如何实现其中的每个步骤。
public void prepareToSave(ISaveContext context) throws CoreException {
}
public void saving(ISaveContext context) throws CoreException {
switch (context.getKind()) {
case ISaveContext.FULL_SAVE:
MyPlugin myPluginInstance = MyPlugin.getDefault();
// save the plug-in state
int saveNumber = context.getSaveNumber();
String saveFileName = "save-" + Integer.toString(saveNumber);
File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
// if we fail to write, an exception is thrown and we do not update the path
myPluginInstance.writeImportantState(f);
context.map(new Path("save"), new Path(saveFileName));
context.needSaveNumber();
break;
case ISaveContext.PROJECT_SAVE:
// get the project related to this save operation
IProject project = context.getProject();
// save its information, if necessary
break;
case ISaveContext.SNAPSHOT:
// This operation needs to be really fast because
// snapshots can be requested frequently by the
// workspace.
break;
}
}
ISaveContext 描述有关保存操作的信息。有三种保存操作:FULL_SAVE、SNAPSHOT 和 PROJECT_SAVE。保存参与者应谨慎执行适用于他们接收到的保存事件种类的处理。例如,快照事件可能发生得极为频繁而且计划允许插件保存它们的临界状态。花较长时间来保存在崩溃事件中可重新计算的状态将拖慢平台的运行速度。
保存号码可用来创建使用序号(save-1、save-2 等)命名的数据保存文件。将每个保存文件映射至独立于保存号码的逻辑文件名(保存)。将插件数据写入相应的文件,并可在以后不知道上次成功的保存操作的特定保存号码的情况下检索插件数据。再次回忆我们在插件的启动代码中看到的此技巧:
IPath location = lastState.lookup(new Path("save"));在保存了数据并映射了文件名之后,调用 needSaveNumber 以指示我们已经积极参与了工作空间保存,并且想要为保存活动指定号码。可以按如上所述使用保存号码来创建数据文件。
public void doneSaving(ISaveContext context) {
MyPlugin myPluginInstance = MyPlugin.getDefault();
// delete the old saved state since it is not necessary anymore
int previousSaveNumber = context.getPreviousSaveNumber();
String oldFileName = "save-" + Integer.toString(previousSaveNumber);
File f = myPluginInstance.getStateLocation().append(oldFileName).toFile();
f.delete();
}
我们在此处清除先前保存操作中的保存信息。我们使用 getPreviousSaveNumber 以获取在先前的保存操作(不是我们刚才完成的操作)中指定的保存编号。我们使用此编号来构造需要删除的文件的名称。注意,我们不使用保存状态的逻辑文件映射,这是因为我们已经映射了当前保存文件编号。
public void rollback(ISaveContext context) {
MyPlugin myPluginInstance = MyPlugin.getDefault();
// since the save operation has failed, delete the saved state we have just written
int saveNumber = context.getSaveNumber();
String saveFileName = "save-" + Integer.toString(saveNumber);
File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
f.delete();
}
在此处删除刚保存的状态。注意,使用当前保存号码来构造刚保存的文件的文件名。不必担心,我们已经将此文件名映射到 ISaveContext 中。保存操作失败时,平台将废弃该上下文。
如果插件在保存生命周期中的任何时间抛出了异常,则将从当前保存操作中除去它,并且将不会获得余下的任何生命周期方法。例如,如果您在保存方法中失败了,则您将不会接收到回滚或完成保存消息。
在将保存参与者添加到工作空间中时,它将返回 ISavedState 对象,该对象描述在插件的上次保存操作期间插件保存的内容 (或者如果插件先前未保存任何状态,则保存的内容为 null)。可以使用此对象来访问前一保存文件中的信息(通过使用保存号码和文件映射),或者处理在激活插件之间发生的更改。
如果使用文件映射来保存根据保存号码来逻辑命名的文件,则可以使用此相同映射来检索上一个所知的保存状态中的数据。
ISaveParticipant saveParticipant = new MyWorkspaceSaveParticipant();
ISavedState lastState =
ResourcesPlugin.getWorkspace().addSaveParticipant(myPluginInstance, saveParticipant);
if (lastState != null) {
String saveFileName = lastState.lookup(new Path("save")).toString();
File f = myPluginInstance.getStateLocation().append(saveFileName).toFile();
// the plugin instance should read any important state from the file.
myPluginInstance.readStateFrom(f);
}
在激活插件之前,回忆一下工作空间中可能会发生的任何数目的资源更改事件。如果想要知道自取消激活您的插件之后发生了哪些更改,即使您不需要保存其它任何数据,也可以使用保存机制来执行此操作。
保存参与者必须请求平台自己保存资源变化。这是作为保存操作的一部分来完成的。
public void saving(ISaveContext context) throws CoreException {
// no state to be saved by the plug-in, but request a
// resource delta to be used on next activation.
context.needDelta();
}
在插件启动期间,可以访问前一保存的状态,并且将为自上次保存后发生的所有更改创建更改事件。
ISaveParticipant saveParticipant = new MyWorkspaceSaveParticipant();
ISavedState lastState =
ResourcesPlugin.getWorkspace().addSaveParticipant(myPluginInstance, saveParticipant);
if (lastState != null) {
lastState.processResourceChangeEvents(new MyResourceChangeReporter());
}
所提供的类必须实现 IResourceChangeListener,正如跟踪资源更改中描述的那样。自上次保存后发生的更改是作为 POST_AUTO_BUILD 资源更改事件的一部分来报告的。
注意:存储在 ISavedState 中的更改事件中不会报告标记更改。必须假定自保存了上一个状态后已经更改了任何标记或所有标记。