`

Workspace Resource框架专题(3)处理工作空间资源更改事件

 
阅读更多
3  处理工作空间资源更改事件
  工作空间API允许工具对它所感兴趣的资源更改事件进行注册。您可以使用资源更改侦听器来对事件作出响应或执行相应动作,甚至自动执行某些任务。例如,资源更改侦听器可以用于管理Bookmarks视图中的条目。从资源中添加或删除书签标记将触发一次资源更改事件。Bookmarks视图则侦听到该事件,并且判断是否需要对它作出响应。并不是所有的事件发生都要求Bookmarks视图作出相应的更改。而是Bookmarks视图所使用的资源更改侦听器可以快速地判断是否有书签标记发生更改,如果需要,作出相应的反应。用户可以看到视图对更改作出的即时反应(为了测试,您可以打开Bookmarks视图,然后向一个文件中添加一个或两个书签)。
3.1  使用工作空间API跟踪更改
  可以使用IWorkspace.addResourceChangeListener(...)方法将资源更改侦听器添加到工作空间中。该方法允许您的侦听器接收来自于更改事件的通知,这些更改事件包括:
●       添加、修改、移动或删除文件。
●       打开或关闭项目。
●       添加或删除标记。
●       构建器事件即将启动或已完成。
  表1-3中所列的接口用于实现对资源更改侦听器的支持,包括支持创建资源更改侦听器、处理接收到的事件以及访问与资源相关联的资源变化(resource delta)。侦听器是实现IResourceChangeListener接口的一个类,其中定义了resourceChanged方法。该方法可以通过传入的IResourceChangeEvent参数查询事件的类型。适当的时候,侦听器可以获得一个IResourceDelta对象,该对象包含更改受事件影响的资源的细节。
表1-3  资源更改事件接口
资源处理接口 描    述
IResourceChangeListener 如果您希望当发生资源更改事件时收到消息,必须实现该接口。当工作空间中资源发生更改时,将会通知资源更改侦听器
IResourceChangeEvent 资源更改事件描述资源所发生的更改。一旦您注册表示对资源更改进行侦听,需要的时候,就会把资源更改事件传递给您
IResourceDelta 资源变化代表了资源树的状态在不同的两个时间点之间所发生的更改。一个资源更改事件包含一个资源变化。该资源变化可以使用访问者模式进行处理
IResourceDeltaVisitor 为了成为资源变化的访问者,您的类必须实现该接口。访问者模式允许您处理资源变化中的每一项
  某些事件类型包含一个IResourceDelta对象,该对象包含了事件所引起的更改的信息。
  我们可以在插件启动的过程中添加资源更改侦听器,但它只能侦听到发生在添加操作之后的资源更改事件。下面的图1-5显示了在Eclipse的一次启动和关闭生命周期内,所发生的更改事件集(A、B、C、D和E)。
   默认情况下,除了对资源属性的操作之外,每一次对资源的更改操作,都会被识别为一次事件,并会被通知给对此感兴趣的资源更改侦听器。正如您可能想象的那样,如果存在大量的更改事件和多个资源侦听器,事件的处理过程将会成为一个性能瓶颈。减少事件的发生次数,则是导致更改事件发生的那段代码的职责。使用IWorkspaceRunnable接口来减少事件发生次数的技术将在本章后续部分的“资源更改事件管理”一节中讨论。



图1-5  带有一个资源更改侦听器的事件处理过程
  一般情况下,用户在使用Eclipse时并不会启动插件,直到有需要时,才会启动。在插件的启动过程中,它可以向工作空间添加资源更改事件。只有那些发生在侦听器添加之后的事件,插件才会收到通知,因此,正如图1-5所示,资源更改侦听器只会收到资源更改事件D和E的通知。
3.2  添加资源更改侦听器
您可以使用下面任何一种方法向工作空间添加资源更改侦听器,之后,您将会收到所侦听的更改事件的通知。
  addResourceChangeListener(
    IResourceChangeListener 1istener)
  addResourceChangeListener(
    IResourceChangeListener listener, int eventMask)
  第一种方法是添加一个基本的侦听器,它将收到发生的所有非构建的资源更改事件(关闭、删除和更改)。第二种方法则允许您在添加侦听器时使用一个事件屏蔽参数,以选择发送到侦听器的资源更改事件类型。通过这种方法,您可以过滤掉任何您认为不需要处理的事件。表1-4列出了各种可以发送到侦听器的资源更改事件类型。
表1-4  资源更改事件类型
更 改 事 件      工作空间 有无资源变化 描    述
PRE_CLOSE 锁定 通知侦听器,项目即将关闭。对于每个打开的项目,在关闭工作空间的过程中也会触发该事件
PRE_DELETE 锁定 通知侦听器,项目即将删除
PRE_BUILD 不锁定 在发生任何自动构建之前通知侦听器。当Eclipse平台检测到需要进行自动构建时,就会广播此事件,而不管实际上是否启用了自动构建功能
POST_BUILD 不锁定 在发生任何自动构建后通知侦听器。在Eclipse平台执行自动构建后广播此事件,而不管实际上是否启用了自动构建功能
POST_CHANGE 锁定 向侦听器通知一次资源更改事件。在POST_BUILD事件通知完成之后,将广播该事件通知。资源变化包含任何由构建器在自动构建过程中产生的更改

  PRE_CLOSE和PRE_DELETE事件只是表示项目的状态而非事件的历史情况。这两种类型的事件对于触发清除操作非常有用,例如删除项目资源在内存中或状态目录中的表示。只有PRE_BUILD和POST_BUILD事件允许您的侦听器在通知周期内创建或者修改资源。这使得不同工具定义的所有POST_CHANGE事件侦听器都有机会对同一资源变化作出反应。|
下面的代码示例,说明了如何查询资源更改事件信息以及如何获取资源变化以便进一步处理。
  public void resourceChanged(IResourceChangeEvent event) {
  switch (event.GetType()) {
  case IResourceChangeEvent.PRE_CLOSE :
  System.out.print1n(
   "Closing: " + event.getResource().getFullPath());
  break;
  case IResourceChangeEvent.PRE_DELETE :
  System.out.println(
   "Deleting : " + event.getResource().getFullPath());
  break;
  case IResourceChangeEvent.PRE_AUTO_BUILD :
  System.out.print1n(" -> Auto build about to run.");
  break;
  case IResourceChangeEvent.POST_AUTO_BUILD :
  System.out.println(
   " -> Auto build complete, visiting the delta...");
  try {
  event.getDelta().accept(
   new Simp1eResourceDe1taVisitor());
  } catch (CoreException e) {
   System.out.println(e);
  }
  break;
  case IResourceChangeEvent.POST_CHANGE :
  System.out.print1n(
   " -> Resource(s) changed, visiting the delta...");
  try {
  event.getDelta().accept(
   new SimpleResourceDeltaVisitor());
  } catch (CoreException e) {
   System.out.println(e);
  }
   }
  }
  该段代码也展示了,当事件提供了一个资源变化时(仅POST_事件),如何从传递给资源更改侦听器的事件中获取资源变化。如上所示,event.getDelta方法可以用于获取一个IResourceDelta对象的引用。除此之外,还需要一个访问者来查找资源变化中所标识的更改。
  您也可以直接访问资源变化以确定是否是您所感兴趣的资源发生了更改。这种方式允许您基于路径来查询资源变化:
  event.getDelta().findMember(IPath);
  相对于访问整个资源变化树的方法,该方法更加高效,但是您必须拥有一个您所感兴趣的具体文件或文件夹,以便进行查询。
  
3.3  资源更改事件触发的时序
  当资源已经以某种方式发生更改,并作为构建事件周期的一部分时,会触发资源更改事件。您无法保证两种类型的事件发送的先后次序(更改事件和构建事件)。
  当资源发生更改时,无论它是添加、修改、删除或移动操作,还是对于资源的标记进行更改,都会触发一次资源更改事件。同样地,项目状态的更改也会触发一次资源更改事件。这些事件均在一个通知周期内被传递。当资源被修改时,也会触发构建事件,然后,这些事件会在不同的通知周期内被传递。
  用一个简单例子来说明这一点。假设您拥有3个资源更改侦听器,一个仅侦听POST_CHANGE事件,一个仅侦听PRE_BUILD事件,另一个同时侦听这两个事件。我们称这些侦听器依次为A、B和C。如果您即将删除一个资源,侦听器A和C将会被调用,并作为更改通知周期的一部分;然后,侦听器B和C被调用,并作为构建通知周期的一部分。够简单吧,让我们继续下面的内容。
  我们假定如下情形,在一次操作调用过程中,产生了5次不同的资源更改。由于这些事件迅速地被触发,工作空间将按照轮流的方式把所有5次更改事件传递给A和C(A、C、A、C等)。传递完这些事件之后,再将构建事件传递给B和C。这些资源更改侦听器只会被调用一次,但是它们可以通过资源变化访问所有5次资源更改的信息。
  下面是试验的结果:如果您的程序从容地产生资源更改,您可能会看见构建事件在更改事件之间默默地暗中进行。您可以在Eclipse平台项目网站eclipse.org的项目页面上以及Eclipse帮助系统中找到关于发送资源更改事件的更为详细的信息。
3.4  访问资源变化
  访问者可以通过访问者模式对资源更改事件所提供的资源变化进行处理。为此,访问者必须实现IResourceDeltaVisitor接口,该接口允许访问者处理资源变化。通过该接口,访问者可以访问每个更改事件,并且实现任何需要进行的处理(参见图1-6)。



图1-6  访问资源变化
  为了创建访问者,请在类中实现IResourceDeltaVisitor接口,该接口要求其实现类拥有一个visit方法。为了获取资源变化并结合访问者进行处理,您可以在资源更改侦听器中使用如下程序代码;
  event.getDelta().accept(new SimpleResourceDeltaVisitor());
  下面是一个实现资源变化访问者中的visit方法的简单示例。
  public boolean visit(IResourceDelta delta)
  throws CoreException {
  IResource res = delta.getResource();
  switch (delta.getKind()) {
  case IResourceDelta.ADDED :
  System.out.println(
   "Resource " + res.getFullPath() + " was added.");
  break;
  case IResourceDelta.REMOVED :
  System.out.println(
   "Resource " + res.getFullPath() + " was removed.");
  break;
  case IResourceDelta.CHANGED :
  System.out.print1n(
   "Resource " + res.getFullPath() + " has changed.");
  break;
  }
  return true; // Continue the visit process.
  }
  该例子通过查询资源变化来标识资源更改的类型。此外,资源变化也包含了更改事件的其他信息。对于PRE_BUILD、POST_BUILD和POST_CHANGE类型的资源更改事件,资源变化还将包含标记的更改信息。
如下示例说明了如何通过变化查找更改的其他详细信息。
  int eventFlag = delta.getFlags();
  if ((eventFlag & IResourceDelta.CONTENT) != 0)
   traceMsg("--> Content Changed");
  if ((eventFlag & IResourceDelta.REPLACED) != 0)
   traceMsg("--> Content Replaced");
  if ((eventFlag & IResourceDelta.REMOVED) != 0)
   traceMsg("--> Removed");
  if ((eventFlag & IResourceDelta.MARKERS) != 0)
   traceMsg("--------------------> Marker Changed");
  关于资源更改事件的各种标志类型在IResourceDelta类中被定义为常量。这些常量已经在表1-5进行了汇总。
表1-5  资源更改事件标志
常量(在IResourceDelta中) 适用的资源 描    述
CONTENT IFile,IFolder 自上次通知以来,该资源在文件系统中的修改时间戳发生了变化。IResource.touch()也会触发一次内容更改通知,即使文件系统中的内容可能并没有发生更改
MOVED_FROM IFile,IFolder,IProject 该资源由另一个位置移动到当前位置。您可以通过调用IResourceDelta.getMoveFromPath查找该资源从何而来
MOVED_TO IFile,IFolder,IProject 该资源被移动到其他位置。您可以通过调用IResourceDelta.getMovedToPath查找该资源被移往何处
OPEN IProject 事件发生之前,项目处于打开状态还是关闭状态。如果项目当前处于打开状态,则它先前处于关闭状态,反之亦然
TYPE IFile,IFolder 资源类型发生了更改。如果事件发生之前,该资源是文件,则当前该资源是一个文件夹,反之亦然
MARKERS 适用于任何资源类型 资源的标记发生了更改。标记是诸如断点、书签、代码添加项(todo item)之类的关于资源的注释。IResourceDelta.getMarkerDeltas()方法用于查找哪些标记发生了更改
ADDED IFile,IFolder,IProject 资源已经被添加到其父资源中
REPLACED IFile,IFolder,IProject 资源被同一位置下的另一资源所替代(即:资源已经被删除而后又再次添加)
DESCRIPTION IProject 资源描述发生了更改
SYNC 适用于任何资源类型 资源的同步信息发生了更改。同步信息用于确定资源是否与远程服务器保持同步,而不是通常本地工具所感兴趣的信息。详细信息请参见API中关于ISynchronizer接口的相关内容
为了找出资源更改事件中所涉及到的标记的变化,可以使用下面的方法。
  IMarkerDe1ta[] markers = delta.getMarkerDeltas();
  for (int i =0; i < markers.length; i++) {
  IMarkerDelta markerDelta = markers[i];
  int kind = markerDelta.getKind();
  System.out.print("\t Marker delta kind: " + kind);
  IMarker marker = markerDelta.getMarker();
  System.out.piint1n("\t Marker itself: "
   + marker + marker.getType());
  System.out.print1n("\t Marker content: "
   + marker.getAttributes());
  System.out.println("<--------------------");
  }
3.5  资源变化内容
  资源变化可以包含多个更改事件的内容。例如,如果您向一个文件夹(aFolder)添加一个文件(a.file),将在资源变化中看到如下更改:
  / changed (workspace root)
  /a.project changed
  /a.project/aFolder changed
  /a.project/aFolder/a.file added
  有些针对资源模型的更改可以触发多个事件。例如,关闭一个项目,将触发PRE_CLOSE事件,以确认一次关闭操作。此外,关闭项目的同时还会从工作空间中删除项目所包含的资源,因此,PRE_BUILD、POST_BUILD和POST_CHANGE资源更改事件也会被触发。如果您在刚添加完a.file文件后关闭当前项目,将在资源变化中看到如下更改:
  / changed (workspace root)
  /a.project changed
  /a.project/aFolder removed
  /a.project/aFolder/a.file removed
  关闭项目时,项目并不会从资源模型中删除,而是以关闭状态存在。但如果删除一个项目,则资源更改事件PRE_DELETE、PRE_BUILD、POST_BUILD和POST_CHANGE会被触发。PRE_DELETE事件包含正在删除的项目,而其他资源更改事件则包含一个资源变化,该资源变化的内容如下:
  / changed (workspace root)
  /a.project removed
  /a.project/aFolder removed
  /a.project/aFolder/a.fi1e removed
--------------------
说明:
参考资料来源--《Eclipse 权威开发指南(第2版)》
这是一本译著,原名《The Java Developer’s Guide to Eclipse》 2nd Edition, 这本还是比较全面和深入的讲解了Eclipse开发中的各个部分的感念和原理的,不适合入门,做过一段时间的开发后阅读比较好。
  • 大小: 17.5 KB
  • 大小: 24.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics