Элементы модели, отображаемые в Eclipse JFace Viewers, иногда загружаются довольно долго. По этой IDeferredWorkbenchAdapter
предоставляет тип IDeferredWorkbenchAdapter
для выборки таких элементов модели в фоновом режиме. К сожалению, этот механизм, кажется, поддерживается только для производных AbstractTreeViewer
через DeferredTreeContentManager
.
Поэтому я разработал собственный собственный DeferredContentManager
… Он позволяет выполнять фоновую загрузку для всех типов StructuredViewer
которые позволяют добавлять и удалять элементы модели. И в этом посте я объясняю, как это работает и как его можно использовать.
В связи с необходимостью (повторного) использования фоновой выборки с помощью TableViewer
я обнаружил только старую и неразрешенную ошибку платформы по этой теме. Но я сомневаюсь, что предложенное решение этой проблемы о внедрении дополнительного менеджера контента для средств просмотра таблиц было бы в любом случае очень разумным. Поэтому я решил попробовать самодельное универсальное решение, основанное на концепциях доступной конкретной реализации дерева.
Отсроченная загрузка контента с помощью JFace Viewers
Основной принцип работы с элементами модели с длительной загрузкой в JFace Viewers прост. Вместо того, чтобы извлекать содержимое в IContentProvider#getElements(Object)
напрямую, извлечение данных делегируется определенному адаптеру, который выполняет его в фоновом задании.
Более того, делегирующая реализация getElements(Object)
возвращает заполнитель . Это показывается зрителем, пока происходит загрузка данных. В то же время собранные данные передаются на задание обновления . Последний добавляет элементы в структурированную программу просмотра. UIJob
обновления является производным от UIJob
поскольку доступ к UIJob
SWT разрешен только из кода, выполняемого UIJob
пользовательского интерфейса.
Наконец, когда фоновая загрузка завершена, задание очистки удаляет заполнитель.
Отложенную выборку содержимого не следует путать с отложенной загрузкой элементов с использованием флага SWT.VIRTUAL
. Хотя оба подхода имеют сходство, виртуальная таблица и деревья обычно полезны для частичной загрузки больших наборов данных по требованию.
Отложенная загрузка полезна для наборов данных разумного размера, которые, тем не менее, могут потребовать много времени для извлечения и, следовательно, могут блокировать поток пользовательского интерфейса. Рассмотрим выборку удаленных данных, например. И если вам интересно, оба подхода, конечно, взаимоисключающие …
IDeferredWorkbenchAdapter
С точки зрения разработчика, IDeferredWorkbenchAdapter
— это путь. Это расширение IWorkbenchAdapter
, которое в целом отвечает за «обеспечение визуального представления и иерархической структуры элементов верстака, позволяя им отображаться в пользовательском интерфейсе без необходимости знать конкретный тип элемента», — как указано в его javadoc .
Расширение объявляет дополнительные методы для поддержки отложенной выборки дочерних элементов данного элемента данных и может быть зарегистрировано фабрикой адаптеров. Рассмотрим простое pojo, которое служит элементом модели, например:
1
2
3
|
public class ModelElement { [...] } |
Чтобы абстрагировать визуальное представление и фоновую загрузку от классов домена, предоставьте соответствующую реализацию адаптера…
1
2
3
4
5
|
public class ModelElementAdapter implements IDeferredWorkbenchAdapter { [...] } |
… И сопоставить оба типа вместе, используя фабрику адаптеров:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public class ModelElementAdapterFactory implements IAdapterFactory { @Override public Object getAdapter( Object adaptableObject, Class adapterType ) { return new ModelElementAdapter(); } @Override public Class[] getAdapterList() { return new Class[] { ModelElement. class }; } } |
Для получения дополнительной информации об использовании IAdaptable
, IWorkbenchAdapter
и IAdaptableFactory
вы можете посмотреть, как я могу использовать IAdaptable и IAdapterFactory? , К сожалению, поставщики содержимого и меток IAdaptable
по умолчанию ожидают, что элементы модели реализуют IAdaptable
. Однако это можно обойти с помощью пользовательских провайдеров .
Следующий тестовый эскиз проверяет, что адаптация элемента работает должным образом:
01
02
03
04
05
06
07
08
09
10
11
|
@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
:
01
02
03
04
05
06
07
08
09
10
|
@Override public void fetchDeferredChildren( Object parent, IElementCollector collector, IProgressMonitor monitor ) { collector.add( loadData( parent ), monitor ); } private Object[] loadData( Object parent ) { return [...] } |
Загрузка данных, loadData()
много времени, очевидно, обрабатывается методом loadData()
. Добавление элементов данных в IElementCollector
запускает задание обновления, упомянутое выше. Как вы можете видеть, выборка данных может быть разделена на несколько этапов, и о прогрессе можно сообщить через данный IProgressMonitor
.
DeferredContentManager
Последнее, что нужно сделать, — это связать механизм, описанный в этом посте, с экземпляром средства просмотра, используемым для отображения элементов модели. Для этой цели DeferredContentManager
может адаптировать произвольные средства просмотра и делегировать извлечение элемента к соответствующей реализации IDeferredWorkbenchAdapter
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class ModelElementContentProvider implements IStructuredContentProvider { DeferredContentManager manager; @Override public void inputChanged( Viewer viewer, Object oldInput, Object newInput ) { TableViewerAdapter adapter = new TableViewerAdapter( ( TableViewer )viewer ); manager = new DeferredContentManager( adapter ); } @Override public Object[] getElements( Object inputElement ) { return manager.getChildren( inputElement ); } [...] } |
Пользовательский IStructuredContentProvider
используется для адаптации зрителя в его методе inputChanged
. Реализация getElements
делегирует диспетчеру контента, который, в свою очередь, делегирует загрузку элемента в адаптер элемента модели, используя DeferredContentManager#getChildren
.
В то время как выборка продолжается, элемент заполнителя возвращается, чтобы показать метку «Ожидание …» во вьюере. Это ситуация, показанная на титульном изображении слева. На правой стороне поиск был завершен, и заполнитель был удален.
StructuredViewerAdapter
Из этого примера становится ясно, как DeferredContentManager
может поддерживать разные типы средств просмотра. Средство просмотра адаптируется менеджером контента с использованием подходящего производного от StructuredViewerAdapter
. В настоящее время доступны только адаптеры по умолчанию для просмотра абстрактных деревьев и таблиц.
Однако написать адаптеры для других типов структурированных вьюеров просто. Следующий фрагмент демонстрирует, например, реализацию ListViewer
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public class ListViewerAdapter extends StructuredViewerAdapter { public ListViewerAdapter( AbstractListViewer listViewer ) { super ( listViewer ); } @Override public void remove( Object element ) { viewer.remove( element ); } @Override public void addElements( Object parent, Object[] children ) { viewer.add( children ); } } |
Использование этого и замена средства просмотра таблиц средством просмотра списка в этом примере приведет к следующему результату:
Здорово! Не так ли?
Вывод
В этом посте было представлено введение в DeferredContentManager
и показано, как он позволяет выполнять фоновую загрузку элементов модели с помощью различных средств просмотра JFace. И если — после всех убедительных объяснений использования, приведенных выше, — вам может быть интересно, где его взять, вы найдете его в репозитории Xiled P2. Менеджер контента является частью функции com.codeaffine.eclipse.ui
:
Если вы хотите взглянуть на код или подать проблему, вы также можете взглянуть на проект Xiled GitHub:
Ссылка: | Отложенное получение элементов модели с помощью JFace Viewers от нашего партнера по JCG Фрэнка Аппеля в блоге Code Affine . |