23.4.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帮助系统中找到关于发送资源更改事件的更为详细的信息。
23.4.4 访问资源变化
访问者可以通过访问者模式对资源更改事件所提供的资源变化进行处理。为此,访问者必须实现IResourceDeltaVisitor接口,该接口允许访问者处理资源变化。通过该接口,访问者可以访问每个更改事件,并且实现任何需要进行的处理(参见图23-6)。

图23-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类中被定义为常量。这些常量已经在表23-5进行了汇总,该表曾作为How you’ve change文章的一部分,发布在eclipse.org网站上。
表23-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("<--------------------");
}
关于标记的定义和实现将在第25章“创建定制的资源标记”一节中讨论。
23.4.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






