我们刚刚了解过如何在可运行程序中对资源更改进行批处理(对资源更改进行批处理)。我们再来看看另一方面。如果想要跟踪插件运行时发生的所有工作空间更改又该怎么办?可向工作空间注册 IResourceChangeListener。将通过 IResourceChangeEvent 对象(用来描述更改)来向侦听器通知更改。
首先必须向工作空间注册资源更改侦听器。
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener( listener, IResourceChangeEvent.POST_CHANGE);
在执行了对工作空间资源的修改之后,将通知侦听器。修改资源的资源 API 方法将触发这些事件,作为描述行为的一部分。资源 API 方法的方法注释显式声明它是否触发了资源更改事件。例如,以下是 IFile.setContents() 注释中所包含的内容:
This method changes resources; these changes will be reported in a subsequent resource change event, including an indication that this file's content have been changed.
通常,创建、删除或更改资源的方法将触发这些事件。读取但不写入资源的方法通常不会触发这些事件。
资源更改事件描述在工作空间中已经发生的更改(或更改集合)的细节。事件中包含资源变化,它描述更改的净效应。例如,如果您在一次批处理中添加了资源,稍后又删除了该资源,则该资源将不会出现在变化中。
资源变化构造为起源于工作空间根目录的树。资源变化树描述下列类型的更改:
要遍历资源变化树,可以实现 IResourceDeltaVisitor 接口,或者使用 IResource.getAffectedChildren 来显式遍历树。资源变化访问器实现这样一种 visit 方法,当资源变化枚举树中的每个更改时,就要调用此方法。
注意:资源变化中不会标识对资源会话属性或者资源持久属性所作的更改。
每当对工作空间进行更改(或一批更改)时,就会发送资源更改事件。另外,对于某些特定工作空间操作也会发送资源更改事件。下表总结了资源更改事件的类型以及是何时报告它们的。
事件类型 |
描述 |
---|---|
PRE_CLOSE |
通知侦听器项目即将关闭。此事件可以用来在关闭项目之前从该项目的内存表示法(例如,会话属性)中抽取和保存所需的信息。(关闭项目时,将除去其内存表示法)。在处理此事件期间,会锁定工作空间(不能更新任何资源)。事件中包含正关闭的项目。 |
PRE_DELETE |
通知侦听器即将删除项目。此事件可以用来执行清理操作,例如,从插件的目录中除去与项目相关的任何保存状态。在进行此事件期间,会锁定工作空间(不更新任何资源)。事件中包含正删除的项目。 |
PRE_AUTOBUILD |
在发生任何自动构建之前通知侦听器。当平台检测到需要进行自动构建时,就会广播此事件,而不管实际上是否启用了自动构建。在进行此事件期间,工作空间未锁定(可以更新资源)。事件包含用来描述自上次报告 POST_CHANGE 事件后发生的更改的资源变化。 |
POST_AUTOBUILD |
在发生任何自动构建后通知侦听器。在平台执行自动构建后广播此事件,而不管实际上是否启用了自动构建。在进行此事件期间,工作空间未锁定(可以更新资源)。事件包含用来描述自上次报告 POST_CHANGE 事件后发生的更改的资源变化。 |
POST_CHANGE |
描述自上次报告 POST_CHANGE 事件后对工作空间进行的一组更改。在单独使用资源更改 API 之后或者在一批工作空间更改中触发。还会在任何 PRE_AUTOBUILD 或 POST_AUTOBUILD 通知完成后触发。事件包含用来描述自上一个 POST_CHANGE 事件后的净更改的资源变化。在进行此事件期间,会锁定工作空间(不能更新任何资源)。 |
以下示例实现基于控制台的资源更改侦听器。为特定类型的事件注册了资源更改侦听器,而将关于这些事件的信息打印至控制台:
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_AUTO_BUILD | IResourceChangeEvent.POST_AUTO_BUILD | IResourceChangeEvent.POST_CHANGE);
侦听器检查每种事件类型,并报告关于被更改的资源的信息,以及发生的更改的种类。尽管此示例用来显示处理所有类型的资源事件的通用侦听器,但是,典型的侦听器只为一种类型的事件注册。
POST_CHANGE 的实现使用另一个类,该类可以用来访问资源变化中的更改。
import org.eclipse.resources.*; import org.eclipse.runtime.*; public class MyResourceChangeReporter implements IResourceChangeListener { public void resourceChanged(IResourceChangeEvent event) { IResource res = event.getResource(); switch (event.getType()) { case IResourceChangeEvent.PRE_CLOSE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to close."); break; case IResourceChangeEvent.PRE_DELETE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to be deleted."); break; case IResourceChangeEvent.POST_CHANGE: System.out.println("Resources have changed."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.PRE_AUTO_BUILD: System.out.println("Auto build about to run."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.POST_AUTO_BUILD: System.out.println("Auto build complete."); event.getDelta().accept(new DeltaPrinter()); break; } } }
DeltaPrinter 类实现 IResourceDeltaVisitor 接口,以查询资源变化。对资源变化中的每个资源更改都会调用 visit() 方法。访问者使用返回值来指示是否应访问子资源的变化。
class DeltaPrinter implements IResourceDeltaVisitor { public boolean visit(IResourceDelta delta) { IResource res = delta.getResource(); switch (delta.getKind()) { case IResourceDelta.ADDED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was added."); break; case IResourceDelta.REMOVED" System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was removed."); break; case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" has changed."); break; } return true; // visit the children } }
可以从提供的资源变化中获取进一步的信息。以下代码段显示可以如何实现 IResourceDelta.CHANGED 事例,以进一步描述资源更改。
... case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(delta.getFullPath()); System.out.println(" has changed."); int flags = delta.getFlags(); if ((flags & IResourceDelta.CONTENT) != 0) { System.out.println("--> Content Change"); } if ((flags & IResourceDelta.REPLACED) != 0) { System.out.println("--> Content Replaced"); } if ((flags & IResourceDelta.MARKERS) != 0) { System.out.println("--> Marker Change"); IMarkerDelta[] markers = delta.getMarkerDeltas(); // if interested in markers, check these deltas } break; ...
有关资源变化、访问器和标记变化的完整描述,参阅 IResourceDelta、IResourceDeltaVisitor 和 IMarkerDelta 的 API 规范。
注意:如果激活了插件,资源更改侦听器对于跟踪对资源的更改是很有用的。如果插件在它的启动代码中注册了资源更改侦听器,则可能在激活插件之前就已经触发了许多资源更改事件。对于插件接收到的第一个资源更改事件中所包含的资源变化,它将不包含自上次激活插件后所作的所有更改。如果需要跟踪在激活插件之间所作的更改,则应当使用为工作空间保存所提供的支持。在工作空间保存参与中对此作了描述。
注意:某些资源更改事件是在处理后台线程时触发的。资源更改侦听器应该是线程安全的。有关用户界面的线程安全的讨论,请参阅线程技术问题。