23.5 资源更改事件管理
workspace.addChangeListener方法允许工具向工作空间中添加资源更改侦听器,这些侦听器可以对任何资源更改作出反应。如果一个工具或用户产生10次资源更改,则资源侦听器将被通知10次。通常情况下,由用户产生的更改比较简单,但是工具可能会在一次操作中产生多次资源更改。如果每次更改均触发一个事件,那么事件的通知和响应处理将会产生巨大的开销。
当您进行资源处理时,可以控制所触发的资源更改事件的数目,这主要通过以下两种方法来实现。第一种方法,您可以使用工作空间API中的run方法来请求工作空间,将资源的更改打包成单个事件。此外,第二种方法是创建一个WorkspaceJob对象,用于对资源处理进行打包,以减少资源事件数目,同时也用于异步执行处理过程。
有必要指出的是,第二种方法将试图限制所发生的资源更改事件的数目,但它并不能保证在请求期间内,仅有一次事件被触发。其他活动的工作空间处理操作可能会导致资源更改事件的触发。这将意味着您所打包的更改事件中,某些事件会先于其他事件通知。接下来,我们将对以上这两种方法进行讨论。此外,本书配套光盘中有大量的例子,说明了如何实现资源更改,以及一个跟踪资源更改事件的视图。
23.5.1 使用IWorkspaceRunnable
您可以创建IWorkspaceRunnable类型的实例或者在代码中实现该接口。IWorkspaceRunnable接口的run方法可以用来包装您的资源处理代码。其中的代码可以通过工作空间API来调用。下面的代码说明了如何使用IWorkspaceRunnable接口在一个项目中创建两个文件夹,并且在整个过程中,仅触发一次事件。
IWorkspaceRunnable workspaceRunnable =
new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor)
throws CoreException {
IFolder folder =
project.getFo1der("IWorkspaceRunnab1e_one");
folder.create(true, true, null);
folder = project.getFo1der("IWorkspaceRunnab1e_one");
folder.create(true, true, null);
}
};
try {
Resources Plugin.getworkspace().run(workspaceRunnable, null);
} catch (CoreException e) {
}
run方法的另一种签名允许您在添加对调度规则(scheduling rule)的支持时,处理IWorspaceRunnable对象。调度规则是一类作业处理控制元素,用于管理可以运行的作业。当一个新作业的调度规则与当前活动作业的规则相冲突时,则新作业将被延迟,直到没有冲突为止。详细内容请参见第29章“使用作业实现响应性和并发性”中的“使用调度规则”一节。
下面这段代码说明了如何使用调度规则来调用上面所介绍的IWorkspaceRunnable接口,以及如何请求在调用的过程中不触发资源更改事件。
try {
ResourcesPlugin.getWorkspace().run(
WorkspaceRunnable,project,IWorkspace.AVOID_UPDATE,null);
} catch (CoreException e) {
e.printStackTrace();
}
在这段代码中,以project参数作为调度规则。事实上,任何工作空间资源都可以作为调度规则使用,这是因为IResource接口扩展了ISchedulingRule接口。而代码中的AVOID_UPDATE参数则用于请求工作空间不触发资源更改事件,直到更改完成为止。
注意:
您也许希望重新温习一下下面这些建立于IWorkspaceRunnable接口之上的可供选择的技术。
● 当您的动作需要用进度条指示器来指示并且必须支持取消操作时,IRunnableContext接口和IRunnableWithProgress接口针对这种情况,实现了另一种管理资源事件的技术。
● 利用WorkspaceModifyOperation类进行资源事件管理的方法则是建立在IRunnableWithProgress所提供的技术之上的。
23.5.2 使用WorkspaceJob类
顾名思义,WorkspaceJob类就是一种作业。关于作业,我们将在第29章“使用作业实现响应性和并发性”中进行讨论。WorkspaceJob类设计的目的在于将对工作空间进行的修改看作可调度的作业。此外,利用这种方式处理作业,所产生的工作空间资源更改并不会触发事件,直到作业完成为止。
下面的代码展示了如何使用WorkspaceJob在一个项目中创建两个文件夹,且在创建完成时仅触发一次事件。
WorkspaceJob workspaceJob = new WorkspaceJob("createFo1der") {
public IStatus runInWorkspace(IProgressMonitor monitor)
throws CoreException {
IFolder folder = project.getFo1der("WorkspaceJob_one");
folder.create(true, true, null);
folder = project.getFo1der("WorkspaceJob_two");
folder.create(true, true, null);
return new Status(IStatus.OK,
"plugin.id", IStatus. OK, "worked", null);
}
};
workspaceJob.schedule();
注意:
WorkspaceJob对象在runInWorkspace方法内实现必需的处理,而Job对象则在run方法内实现必需的处理。WorkspaceJob类扩展了InternalWorkspaceJob类。该超类实现了在延迟资源更改事件通知的同时,执行runInWorkspace方法所必需的处理
23.5.3 使用工作空间调度规则工厂
当使用刚才所讨论的run方法时,您也许需要将调度规则作为run方法的部分参数;或者当您使用一个Job对象执行某些异步处理时,也可能需要用到调度规则。正如您将在第29章“使用作业实现响应性和并发性”中学到的一样,调度规则适用于任何类型的作业。为了我们在此讨论的目的,您只需将调度规则看作是“门卫”(gatekeeper)一样,由它来决定您的处理请求何时进行。结合资源来使用调度规则可以防止对资源的访问发生冲突。
任何IResource类型的实例都可以作为调度规则来使用,但是使用单一的资源作为调度规则,可能并没有指明您将要产生的更改的作用域。为此,您可以使用工作空间的getRuleFactory方法来获取一个IResourceRuleFactory类型的对象。该工厂包含诸如createRule、deleteRule和markerRule之类的方法,您可以根据需要使用不同的方法名以及传入不同的IResource参数,以返回满足需要的调度规则。与直接使用给定的工作空间资源作为调度规则相比,这些方法返回的规则更为合适。例如,IResourceRuleFactory工厂中的deleteRule方法返回的调度规则,并不是资源本身作为删除资源的调度规则,而是该资源的父资源。
通过使用IResourceRuleFactory类,您相当于允许使用工作空间的体系结构关系来代表您正确创建的调度规则。不仅如此,IResourceRuleFactory类还被资源编程API所使用,如IResource.move使用它来实现移动请求的受控处理。
关于调度规则的额外信息请参见第29章“使用作业实现响应性和并发性”。






