如何在 Vaadin 中实现延迟加载树?
How to implement a lazy loading tree in Vaadin?
我在数据库中有一个相当大的树,加载所有项目并将它们添加到 HierarchicalContainer
在启动时表现不佳。
相反,我想在单击时加载树项的子项。
其实早一点,因为我不想 areChildrenAllowed()
或 hasChildren()
到 return 错误的值。
我希望在 JFace 中找到类似的东西 TreeViewer is used ITreeContentProvider。
是否有关于此主题的任何示例或最佳实践描述?
这是我目前得到的:
public class OutputNodeContainer extends HierarchicalContainer {
/** the view service */
private IViewService service = CommonPlugin.getService(IViewService.class);
private List<Object> childrenRead = new ArrayList<>();
@Override
public boolean areChildrenAllowed(Object itemId) {
if (!childrenRead.contains(itemId)) {
OutputNode node = (OutputNode) itemId;
List<OutputNode> children = service.getChildren(node.getNodeId(), false);
for (OutputNode child : children) {
addItem(child);
setParent(child, itemId);
}
childrenRead.add(itemId);
return !children.isEmpty();
}
return super.areChildrenAllowed(itemId);
}
}
但是在 addItem(child);
我 运行 进入这个异常:
java.lang.IllegalStateException: A connector should not be marked as dirty while a response is being written.
at com.vaadin.ui.ConnectorTracker.markDirty(ConnectorTracker.java:489)
at com.vaadin.server.AbstractClientConnector.markAsDirty(AbstractClientConnector.java:143)
at com.vaadin.ui.Tree.markAsDirty(Tree.java:348)
at com.vaadin.ui.AbstractSelect.fireItemSetChange(AbstractSelect.java:1746)
at com.vaadin.ui.AbstractSelect.containerItemSetChange(AbstractSelect.java:1713)
at com.vaadin.ui.Tree.containerItemSetChange(Tree.java:992)
at com.vaadin.data.util.AbstractContainer.fireItemSetChange(AbstractContainer.java:246)
at com.vaadin.data.util.HierarchicalContainer.fireItemSetChange(HierarchicalContainer.java:436)
at com.vaadin.data.util.IndexedContainer.fireItemSetChange(IndexedContainer.java:640)
at com.vaadin.data.util.HierarchicalContainer.enableAndFireContentsChangeEvents(HierarchicalContainer.java:460)
at com.vaadin.data.util.HierarchicalContainer.addItem(HierarchicalContainer.java:489)
at ch.scodi.vaadin.viewer.OutputNodeContainer.areChildrenAllowed(OutputNodeContainer.java:78)
at com.vaadin.ui.Tree.areChildrenAllowed(Tree.java:864)
at com.vaadin.ui.Tree.paintContent(Tree.java:732)
at com.vaadin.server.LegacyPaint.paint(LegacyPaint.java:65)
at com.vaadin.server.communication.LegacyUidlWriter.write(LegacyUidlWriter.java:82)
at com.vaadin.server.communication.UidlWriter.write(UidlWriter.java:143)
at com.vaadin.server.communication.UIInitHandler.getInitialUidl(UIInitHandler.java:284)
at com.vaadin.server.communication.UIInitHandler.synchronizedHandleRequest(UIInitHandler.java:80)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1422)
... 63 common frames omitted
尽管在 Vaadin 文档中说 Tree
的延迟加载是 not supported,但我设法实现了以下 延迟加载 Hierarchical
接口。
将所有元素存储在本地结构中非常重要(在我的例子中是 HashMap
hierarchy
),不要多次读取元素这是行不通的。我认为是因为 Vaadin 不使用 equals()
和 hashCode()
.
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.softmodeler.common.CommonPlugin;
import com.softmodeler.model.OutputNode;
import com.softmodeler.service.IViewService;
import com.vaadin.data.Container.Hierarchical;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItem;
/**
* @author Flavio Donzé
* @version 1.0
*/
public class OutputNodeHierachical implements Hierarchical {
private static final long serialVersionUID = 8289589835030184018L;
/** the view service */
private IViewService service = CommonPlugin.getService(IViewService.class);
/** collection of all root nodes */
private List<OutputNode> rootNodes = null;
/** parent=>children mapping */
private Map<OutputNode, List<OutputNode>> hierarchy = new HashMap<>();
/**
* constructor
*
* @param rootNodes collection of all root nodes
*/
public OutputNodeHierachical(List<OutputNode> rootNodes) {
this.rootNodes = Collections.unmodifiableList(rootNodes);
addToHierarchy(rootNodes);
}
@Override
public Collection<?> getChildren(Object itemId) {
try {
List<OutputNode> children = hierarchy.get(itemId);
if (children == null) {
OutputNode node = (OutputNode) itemId;
children = service.getChildren(node.getNodeId(), false);
hierarchy.put(node, children);
// add children to hierarchy, their children will be added on click
addToHierarchy(children);
}
return children;
} catch (Exception e) {
VaadinUtil.handleException(e);
}
return null;
}
/**
* add each element to the hierarchy without their children hierarchy(child=>null)
*
* @param children elements to add
*/
private void addToHierarchy(List<OutputNode> children) {
for (OutputNode child : children) {
hierarchy.put(child, null);
}
}
@Override
public boolean areChildrenAllowed(Object itemId) {
return !((OutputNode) itemId).getChilds().isEmpty();
}
@Override
public boolean hasChildren(Object itemId) {
return !((OutputNode) itemId).getChilds().isEmpty();
}
@Override
public Object getParent(Object itemId) {
String parentId = ((OutputNode) itemId).getParentId();
for (OutputNode node : hierarchy.keySet()) {
if (node.getNodeId().equals(parentId)) {
return node;
}
}
return null;
}
@Override
public Collection<?> rootItemIds() {
return rootNodes;
}
@Override
public boolean isRoot(Object itemId) {
return rootNodes.contains(itemId);
}
@Override
public Item getItem(Object itemId) {
return new BeanItem<OutputNode>((OutputNode) itemId);
}
@Override
public boolean containsId(Object itemId) {
return hierarchy.containsKey(itemId);
}
@Override
public Collection<?> getItemIds() {
return hierarchy.keySet();
}
@Override
public int size() {
return hierarchy.size();
}
@Override
public boolean setParent(Object itemId, Object newParentId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Object addItem() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean removeItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Class<?> getType(Object propertyId) {
throw new UnsupportedOperationException();
}
@Override
public Collection<?> getContainerPropertyIds() {
throw new UnsupportedOperationException();
}
@Override
public Property<?> getContainerProperty(Object itemId, Object propertyId) {
throw new UnsupportedOperationException();
}
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}
像这样将容器添加到 Tree
:
OutputNodeHierachical dataSource = new OutputNodeHierachical(rootNodes);
Tree mainTree = new Tree();
mainTree.setSizeFull();
mainTree.setContainerDataSource(dataSource);
mainTree.addItemClickListener(new ItemClickListener() {
private static final long serialVersionUID = -413371711541672605L;
@Override
public void itemClick(ItemClickEvent event) {
OutputNode node = (OutputNode) event.getItemId();
openObject(node.getObjectId());
}
});
我在数据库中有一个相当大的树,加载所有项目并将它们添加到 HierarchicalContainer
在启动时表现不佳。
相反,我想在单击时加载树项的子项。
其实早一点,因为我不想 areChildrenAllowed()
或 hasChildren()
到 return 错误的值。
我希望在 JFace 中找到类似的东西 TreeViewer is used ITreeContentProvider。
是否有关于此主题的任何示例或最佳实践描述?
这是我目前得到的:
public class OutputNodeContainer extends HierarchicalContainer {
/** the view service */
private IViewService service = CommonPlugin.getService(IViewService.class);
private List<Object> childrenRead = new ArrayList<>();
@Override
public boolean areChildrenAllowed(Object itemId) {
if (!childrenRead.contains(itemId)) {
OutputNode node = (OutputNode) itemId;
List<OutputNode> children = service.getChildren(node.getNodeId(), false);
for (OutputNode child : children) {
addItem(child);
setParent(child, itemId);
}
childrenRead.add(itemId);
return !children.isEmpty();
}
return super.areChildrenAllowed(itemId);
}
}
但是在 addItem(child);
我 运行 进入这个异常:
java.lang.IllegalStateException: A connector should not be marked as dirty while a response is being written.
at com.vaadin.ui.ConnectorTracker.markDirty(ConnectorTracker.java:489)
at com.vaadin.server.AbstractClientConnector.markAsDirty(AbstractClientConnector.java:143)
at com.vaadin.ui.Tree.markAsDirty(Tree.java:348)
at com.vaadin.ui.AbstractSelect.fireItemSetChange(AbstractSelect.java:1746)
at com.vaadin.ui.AbstractSelect.containerItemSetChange(AbstractSelect.java:1713)
at com.vaadin.ui.Tree.containerItemSetChange(Tree.java:992)
at com.vaadin.data.util.AbstractContainer.fireItemSetChange(AbstractContainer.java:246)
at com.vaadin.data.util.HierarchicalContainer.fireItemSetChange(HierarchicalContainer.java:436)
at com.vaadin.data.util.IndexedContainer.fireItemSetChange(IndexedContainer.java:640)
at com.vaadin.data.util.HierarchicalContainer.enableAndFireContentsChangeEvents(HierarchicalContainer.java:460)
at com.vaadin.data.util.HierarchicalContainer.addItem(HierarchicalContainer.java:489)
at ch.scodi.vaadin.viewer.OutputNodeContainer.areChildrenAllowed(OutputNodeContainer.java:78)
at com.vaadin.ui.Tree.areChildrenAllowed(Tree.java:864)
at com.vaadin.ui.Tree.paintContent(Tree.java:732)
at com.vaadin.server.LegacyPaint.paint(LegacyPaint.java:65)
at com.vaadin.server.communication.LegacyUidlWriter.write(LegacyUidlWriter.java:82)
at com.vaadin.server.communication.UidlWriter.write(UidlWriter.java:143)
at com.vaadin.server.communication.UIInitHandler.getInitialUidl(UIInitHandler.java:284)
at com.vaadin.server.communication.UIInitHandler.synchronizedHandleRequest(UIInitHandler.java:80)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1422)
... 63 common frames omitted
尽管在 Vaadin 文档中说 Tree
的延迟加载是 not supported,但我设法实现了以下 延迟加载 Hierarchical
接口。
将所有元素存储在本地结构中非常重要(在我的例子中是 HashMap
hierarchy
),不要多次读取元素这是行不通的。我认为是因为 Vaadin 不使用 equals()
和 hashCode()
.
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.softmodeler.common.CommonPlugin;
import com.softmodeler.model.OutputNode;
import com.softmodeler.service.IViewService;
import com.vaadin.data.Container.Hierarchical;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItem;
/**
* @author Flavio Donzé
* @version 1.0
*/
public class OutputNodeHierachical implements Hierarchical {
private static final long serialVersionUID = 8289589835030184018L;
/** the view service */
private IViewService service = CommonPlugin.getService(IViewService.class);
/** collection of all root nodes */
private List<OutputNode> rootNodes = null;
/** parent=>children mapping */
private Map<OutputNode, List<OutputNode>> hierarchy = new HashMap<>();
/**
* constructor
*
* @param rootNodes collection of all root nodes
*/
public OutputNodeHierachical(List<OutputNode> rootNodes) {
this.rootNodes = Collections.unmodifiableList(rootNodes);
addToHierarchy(rootNodes);
}
@Override
public Collection<?> getChildren(Object itemId) {
try {
List<OutputNode> children = hierarchy.get(itemId);
if (children == null) {
OutputNode node = (OutputNode) itemId;
children = service.getChildren(node.getNodeId(), false);
hierarchy.put(node, children);
// add children to hierarchy, their children will be added on click
addToHierarchy(children);
}
return children;
} catch (Exception e) {
VaadinUtil.handleException(e);
}
return null;
}
/**
* add each element to the hierarchy without their children hierarchy(child=>null)
*
* @param children elements to add
*/
private void addToHierarchy(List<OutputNode> children) {
for (OutputNode child : children) {
hierarchy.put(child, null);
}
}
@Override
public boolean areChildrenAllowed(Object itemId) {
return !((OutputNode) itemId).getChilds().isEmpty();
}
@Override
public boolean hasChildren(Object itemId) {
return !((OutputNode) itemId).getChilds().isEmpty();
}
@Override
public Object getParent(Object itemId) {
String parentId = ((OutputNode) itemId).getParentId();
for (OutputNode node : hierarchy.keySet()) {
if (node.getNodeId().equals(parentId)) {
return node;
}
}
return null;
}
@Override
public Collection<?> rootItemIds() {
return rootNodes;
}
@Override
public boolean isRoot(Object itemId) {
return rootNodes.contains(itemId);
}
@Override
public Item getItem(Object itemId) {
return new BeanItem<OutputNode>((OutputNode) itemId);
}
@Override
public boolean containsId(Object itemId) {
return hierarchy.containsKey(itemId);
}
@Override
public Collection<?> getItemIds() {
return hierarchy.keySet();
}
@Override
public int size() {
return hierarchy.size();
}
@Override
public boolean setParent(Object itemId, Object newParentId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Object addItem() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean removeItem(Object itemId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Class<?> getType(Object propertyId) {
throw new UnsupportedOperationException();
}
@Override
public Collection<?> getContainerPropertyIds() {
throw new UnsupportedOperationException();
}
@Override
public Property<?> getContainerProperty(Object itemId, Object propertyId) {
throw new UnsupportedOperationException();
}
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type, Object defaultValue) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}
像这样将容器添加到 Tree
:
OutputNodeHierachical dataSource = new OutputNodeHierachical(rootNodes);
Tree mainTree = new Tree();
mainTree.setSizeFull();
mainTree.setContainerDataSource(dataSource);
mainTree.addItemClickListener(new ItemClickListener() {
private static final long serialVersionUID = -413371711541672605L;
@Override
public void itemClick(ItemClickEvent event) {
OutputNode node = (OutputNode) event.getItemId();
openObject(node.getObjectId());
}
});