Eclipse JFace Viewers显示的模型元素有时需要花费大量时间来加载。 因此, 工作台提供了IDeferredWorkbenchAdapter
类型以在后台获取此类模型元素。 不幸的是,似乎仅通过DeferredTreeContentManager
派生的AbstractTreeViewer
支持此机制。
因此,我开发了自己的通用DeferredContentManager
…它可以为允许添加和删除模型元素的所有StructuredViewer
类型进行后台加载。 在这篇文章中,我解释了它是如何工作的以及如何使用。
在需要(重新)使用TableViewer
进行后台获取的情况下,我仅发现了一个与该主题有关的古老且尚未解决的平台错误 。 但是,我怀疑问题所提议的为表查看器实现额外内容管理器的解决方案是否会非常明智。 因此,我决定尝试一个基于可用树特定实现的概念的自制通用解决方案。
使用JFace Viewer延迟获取内容
在JFace Viewers中处理长加载模型元素的基本原理很简单。 与其直接在IContentProvider#getElements(Object)
获取内容, IContentProvider#getElements(Object)
数据检索委托给在后台作业中执行该操作的特定适配器。
此外,委托的getElements(Object)
实现返回一个placeholder 。 只要发生数据加载,查看器就会显示出来。 同时,收集的数据将转发到更新作业 。 后者将元素附加到结构化查看器。 由于仅允许从UI线程执行的代码进行SWT小部件访问,因此更新作业是UIJob
。
最后,在完成后台获取后,清理作业将删除占位符。
不应将延迟获取内容与使用SWT.VIRTUAL
标志的元素的延迟加载相混淆。 尽管两种方法之间存在相似之处,但虚拟表和树通常可用于按需加载大型数据集。
延迟加载对于大小合理的数据集很有帮助,但是,数据集的检索可能很耗时,因此会阻塞UI线程。 例如,考虑获取远程数据。 万一您想知道,这两种方法当然是互斥的 ……
IDeferredWorkbenchAdapter
从开发人员的角度来看, IDeferredWorkbenchAdapter
是必经之路。 它是IWorkbenchAdapter
的扩展,通常负责“为工作台元素提供可视化表示和层次结构,使它们可以在UI中显示而不必知道元素的具体类型”(如其javadoc所述) 。
该扩展声明了其他方法来支持对给定数据元素的子代进行延迟获取,并且可以由适配器工厂进行注册。 考虑一个简单的pojo作为模型元素,例如:
public class ModelElement {[...]
}
为了从域类中抽象视觉呈现和后台加载,请提供适当的适配器实现…
public class ModelElementAdapterimplements IDeferredWorkbenchAdapter
{[...]
}
…并使用适配器工厂将这两种类型映射在一起:
public class ModelElementAdapterFactoryimplements IAdapterFactory
{@Overridepublic Object getAdapter( Object adaptableObject, Class adapterType ) {return new ModelElementAdapter();}@Overridepublic Class[] getAdapterList() {return new Class[] { ModelElement.class };}
}
有关使用IAdaptable
, IWorkbenchAdapter
和IAdaptableFactory
更多信息,您可以看看如何使用IAdaptable和IAdapterFactory? 。 遗憾的是,默认工作台内容和标签提供程序希望模型元素实现IAdaptable
。 但是,可以使用自定义提供程序来规避此问题。
以下测试草图验证了元素适应是否按预期进行:
@Test
public void testAdapterRegistration() {IAdapterManager manager = Platform.getAdapterManager();ModelElementAdapterFactory factory = new ModelElementAdapterFactory();manager.registerAdapters( factory, ModelElement.class );Object actual = manager.getAdapter( new ModelElement(), ModelElement.class );assertThat( actual ).isInstanceOf( ModelElementAdapter.class );
}
现在是时候实现ModelElementAdapter
的数据检索功能了。 这是通过fetchDeferredChildren
方法完成的:
@Override
public void fetchDeferredChildren(Object parent, IElementCollector collector, IProgressMonitor monitor )
{collector.add( loadData( parent ), monitor );
}private Object[] loadData( Object parent ) {return [...]
}
费时的数据加载显然由loadData()
方法处理。 将数据元素添加到IElementCollector
会触发上述更新作业。 如您所见,可以通过几个步骤来划分数据获取,并且可以通过给定的IProgressMonitor
报告进度。
DeferredContentManager
最后要做的是将本文中描述的机制与用于描述模型元素的查看器实例连接起来。 为此, DeferredContentManager
可以调整任意查看器并将元素检索委托给相应的IDeferredWorkbenchAdapter
实现。
class ModelElementContentProviderimplements IStructuredContentProvider
{DeferredContentManager manager;@Overridepublic void inputChanged(Viewer viewer, Object oldInput, Object newInput ){TableViewerAdapter adapter = new TableViewerAdapter( ( TableViewer )viewer );manager = new DeferredContentManager( adapter );}@Overridepublic Object[] getElements( Object inputElement ) {return manager.getChildren( inputElement );}[...]
}
定制的IStructuredContentProvider
用于在其inputChanged
方法中调整查看器。 getElements
的实现将委托给内容管理器,后者再使用DeferredContentManager#getChildren
将元素加载委托给模型元素适配器。
在进行提取时,将返回一个占位符元素,以在查看器中显示“ Pending…”标签。 这是左侧标题图像中所示的情况。 在右侧,检索已完成,并且占位符已删除。
StructuredViewerAdapter
查看示例,可以清楚地了解DeferredContentManager
如何支持不同的查看器类型。 内容管理器使用适当的派生StructuredViewerAdapter
来修改查看器。 目前,只有用于抽象树形和表形查看器的默认适配器可用。
但是,直接为其他结构化查看器类型编写适配器是很容易的。 以下代码段显示了例如ListViewer
的实现:
public class ListViewerAdapterextends StructuredViewerAdapter
{public ListViewerAdapter( AbstractListViewer listViewer ) {super( listViewer );}@Overridepublic void remove( Object element ) {viewer.remove( element );}@Overridepublic void addElements( Object parent, Object[] children ) {viewer.add( children );}
}
在示例中,使用此选项并将表查看器替换为列表查看器将导致以下结果:
凉! 是不是
结论
这篇文章介绍了DeferredContentManager
并展示了它如何启用使用不同的JFace Viewer进行的模型元素的后台加载。 并且,在上面引人注目的用法解释之后,如果您可能想知道从哪里获得它,那么您将在Xiliary P2存储库中找到一个。 内容管理器是com.codeaffine.eclipse.ui
功能的一部分:
- http://fappel.github.io/xiliary
如果您想看一下代码或提出问题,也可以看一下Xiliary GitHub项目:
- https://github.com/fappel/xiliary
翻译自: https://www.javacodegeeks.com/2014/12/deferred-fetching-of-model-elements-with-jface-viewers.html