跟踪资源更改

资源插件中包含一种事件机制,将对资源所作的更改通知给感兴趣的用户。如果需要在插件正在运行时保持跟踪对资源树的更改, 则可以向工作区注册 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.

通常,创建、删除或更改资源的方法将触发这些事件。读取但不写入资源的方法通常不会触发这些事件。

批处理更改和资源变化

如果需要同时修改一些资源,则可以对资源更改 API 调用进行批处理,以便将对整组更改只发送一个资源更改事件。IWorkspace.run(runnable, monitor) 用来批处理执行操作。当完成指定的可运行程序(runnable)时,将只把资源更改事件发送给已注册的侦听器。在可运行程序中创建的所有附加(嵌套)可运行程序将被看作是父代批处理操作的一部分, 而在那些可运行程序中所作的资源更改将出现在父代的资源更改通知中。

应当尽可能地对更改进行批处理,以限制广播许多微小更改所造成的开销。如果未能使用批处理,则可能将使系统中的资源更改通知和自动构建暴增。

资源更改事件描述在工作区中已经发生的更改(或更改集合)的细节。事件中包含资源变化,它描述更改的效应。例如,如果您在一次批处理中添加了资源,稍后又删除了该资源,则该资源将不会出现在变化中。

资源变化构造为起源于工作区根目录的树。资源变化树描述下列类型的更改:

要遍历资源变化树,可以实现 IResourceDeltaVisitor 接口, 或者使用 IResource.getAffectedChildren 来显式遍历树。资源变化访问器实现这样一种 visit 方法, 当资源变化枚举树中的每个更改时,就要调用此方法。

注意:资源变化中不会标识对资源会话属性或者资源持久属性所作的更改。

资源更改事件

每当对工作区进行更改(或一批更改)时,就会发送资源更改事件。另外,对于某些特定工作区操作也会发送资源更改事件。下表总结了资源更改事件的类型以及是何时报告它们的。

事件类型

描述

PRE_CLOSE

通知侦听器项目即将关闭。此事件可以用来在关闭项目之前从该项目的内存表示法(例如,会话属性)中抽取和保存所需的信息。(关闭项目时,将丢弃其内存表示法)。在处理此事件期间,会锁定工作区(不能更新任何资源)。事件中包含正关闭的项目。

PRE_DELETE

通知侦听器即将删除项目。此事件可以用来执行清理操作,例如,从插件的目录中除去与项目相关的任何保存状态。在进行此事件期间,会锁定工作区(不更新任何资源)。事件中包含正删除的项目。

PRE_AUTOBUILD

在发生任何自动构建之前通知侦听器。当平台检测到需要进行自动构建时,就会广播此事件, 而不管实际上是否启用了自动构建。在进行此事件期间,工作区锁定(可以更新资源)。事件包含用来描述自上次报告 POST_CHANGE 事件后发生的更改的资源变化。

POST_AUTOBUILD

在发生任何自动构建后通知侦听器。在平台执行自动构建后广播此事件,而不管实际上是否启用了自动构建。在进行此事件期间,工作区锁定(可以更新资源)。事件包含用来描述自上次报告 POST_CHANGE 事件后发生的更改的资源变化。

POST_CHANGE

描述自上次报告 POST_CHANGE 事件后对工作区进行的一组更改。在单独使用资源更改 API 之后或者在一批工作区更改中触发。还会在任何 PRE_AUTOBUILDPOST_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;
   ...

有关资源变化、访问器和标记变化的完整描述, 参考 IResourceDeltaIResourceDeltaVisitorIMarkerDelta 的 API 规范。

注意:如果激活了插件,资源更改侦听器对于跟踪对资源的更改是很有用的。如果插件在它的启动代码中注册了资源更改侦听器, 则可能在激活插件之前就已经触发了许多资源更改事件。对于插件接收到的第一个资源更改事件中所包含的资源变化,它将不包含自上次激活插件后所作的所有更改。如果需要跟踪在激活插件之间所作的更改, 则应当使用为工作区保存所提供的支持。在工作区保存参与中对此作了描述。

Copyright IBM Corporation and others 2000, 2003.