我正在使用Netbeans 7.2开发JavaFX 2.2应用程序。我正在使用树视图,并且扩展了TreeCell以便为每个TreeItem提供带有MenuItem且具有“ Collpase All”功能的上下文菜单。树视图的最大深度级别为4。当用户右键单击级别2的TreeItem并单击“全部折叠” MenuItem时,我要折叠级别3的所有TreeItem(setExpanded(false))。在下面,您可以看到我正在使用的代码。我的问题是此操作的内存和CPU成本。我在第3级上插入了250个TreeItem。一次合拢所有操作的成本是每次合拢大约需要200MB内存,而单击和花费的时间约为2s!我的开发人员计算机的CPU是Intel i5(3.3GHz),我有8GB的内存。这个数量的硬件成本正常吗,或者我在代码中做错了什么?我使用错误的方式折叠它们吗?
此类管理TreeView。从数据库加载数据,重新加载它们,知道选定的TreeItem并展开/折叠选定的子TreeItems。
public final class TargetTree extends SqlConnectionManager {
private TreeView tree;
private TreeItem selectedItem;
private TargetTree() {
super();
this.tree = null;
this.selectedItem = null;
}
private TargetTree(TreeView tree) {
super();
this.tree = tree;
this.selectedItem = null;
}
public static TargetTree construct(TreeView tree) {
if (tree == null) {
return null;
}
TargetTree targetTree = new TargetTree(tree);
targetTree.load();
return targetTree;
}
public void reload() {
// Clear current tree.
if (tree.getRoot() != null) {
for (int i = 0; i < tree.getRoot().getChildren().size(); i++) {
tree.getRoot().getChildren().clear();
}
tree.setRoot(null);
}
this.load();
}
public void prune() {
//TODO
}
private void load() {
// New root Item.
final TreeItem<Object> treeRoot = new TreeItem<>((Object) "Root");
treeRoot.setExpanded(true);
// This integers help to find when to build a new department/section/measure.
int lastDepartmentId = -1;
int lastSectionId = -1;
int lastMeasureId = -1;
int lastTargetId = -1;
//The temp treeitems.
TreeItem<Object> departmentTreeItem = null;
TreeItem<Object> sectionTreeItem = null;
TreeItem<Object> measureTreeItem = null;
TreeItem<Object> targetTreeItem = null;
// Get the new TreeItems from the database.
super.errorMessage = "";
try {
// Establishing connection with db.
super.openConnection();
// Query to be executed. Selects everything from the database.
preparedStmt = connection.prepareStatement(
"SELECT.....ORDER BY....;");
resultSet = preparedStmt.executeQuery();
while (resultSet.next()) {
// Department Creation.
if (lastDepartmentId != resultSet.getInt("departmentId")) {
final Department department = Department.initEmpty();
department.setId(resultSet.getInt("departmentId"));
department.setName(resultSet.getString("departmentName"));
// Create the treeitem for this department.
departmentTreeItem = new TreeItem<>((Object) department);
departmentTreeItem.setExpanded(true);
treeRoot.getChildren().add(departmentTreeItem);
// Reset the children ids to ensure that they will be recreated.
lastDepartmentId = resultSet.getInt("departmentId");
lastSectionId = -1;
lastMeasureId = -1;
lastTargetId = -1;
}
// Section Creation.
if (lastSectionId != resultSet.getInt("sectionId")) {
final Section section = Section.initEmpty();
section.setId(resultSet.getInt("sectionId"));
section.setName(resultSet.getString("sectionName"));
// Create the treeitem for this section.
sectionTreeItem = new TreeItem<>((Object) section);
sectionTreeItem.setExpanded(true);
departmentTreeItem.getChildren().add(sectionTreeItem);
// Reset the children ids to ensure that they will be recreated.
lastSectionId = resultSet.getInt("sectionId");
lastMeasureId = -1;
lastTargetId = -1;
}
// Measure Creation.
if (lastMeasureId != resultSet.getInt("measureId")) {
final Measure measure = Measure.initEmpty();
measure.setId(resultSet.getInt("measureId"));
measure.setLastname(resultSet.getString("measureLastname"));
measure.setFirstname(resultSet.getString("measureFirstName"));
// Create the treeitem for this measure.
measureTreeItem = new TreeItem<>((Object) measure);
measureTreeItem.setExpanded(true);
sectionTreeItem.getChildren().add(measureTreeItem );
// Reset the children ids to ensure that they will be recreated.
lastMeasureId = resultSet.getInt("measureId");
lastTargetId = -1;
}
// Target Creation.
if (lastTargetId != resultSet.getInt("targetId")) {
final Target target = Target.initEmpty();
target.setId(resultSet.getInt("targetId"));
target.setText(resultSet.getString("targetText"));
// Create the treeitem for this target.
targetTreeItem = new TreeItem<>((Object) target);
targetTreeItem.setExpanded(false);
measureTreeItem.getChildren().add(targetTreeItem);
// Reset the children ids to ensure that they will be recreated.
lastTargetId = resultSet.getInt("targetId");
}
}
closeAll();
} catch (SQLException ex) {
super.errorMessage = ex.getMessage();
}
tree.setRoot(treeRoot);
final TargetTree targetTree = this;
tree.setCellFactory(new Callback<TreeView<Object>, TreeCell<Object>>() {
@Override
public TreeCell<Object> call(TreeView<Object> p) {
return new TargetTreeCell(targetTree);
}
});
// Select a Tree Item.
tree.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
selectedItem = (TreeItem) newValue;
}
});
}
public void collapseChildren() {
Thread thread = new Thread(new Task<Void>() {
@Override
protected Void call() throws Exception {
Platform.runLater(new Runnable() {
@Override
public void run() {
for (int i = 0; i < selectedItem.getChildren().size(); i++) {
TreeItem<Object> current = (TreeItem<Object>) selectedItem.getChildren().get(i);
if (!current.isLeaf()) {
current.setExpanded(false);
}
current = null;
}
selectedItem.setExpanded(false);
System.gc();
}
});
return null;
}
});
thread.setDaemon(true);
thread.start();
}
public void expandChildren() {
Thread thread = new Thread(new Task<Void>() {
@Override
protected Void call() throws Exception {
Platform.runLater(new Runnable() {
@Override
public void run() {
for (int i = 0; i < selectedItem.getChildren().size(); i++) {
TreeItem<Object> current = (TreeItem<Object>) selectedItem.getChildren().get(i);
if (!current.isLeaf()) {
current.setExpanded(true);
}
current = null;
}
selectedItem.setExpanded(true);
System.gc();
}
});
return null;
}
});
thread.setDaemon(true);
thread.start();
}
}
下面是自定义TreeCell类。
public class TargetTreeCell extends TreeCell<Object> {
private TargetTree targetTree;
public TargetTreeCell(TargetTree targetTree) {
super();
this.targetTree = targetTree;
}
@Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
if (item instanceof Target) {
initTarget(item);
} else if (item instanceof Measure) {
initMeasure(item);
} else if (item instanceof Section) {
initSection(item);
} else if (item instanceof Department) {
initDepartment(item);
} else if (item instanceof String) {
initRoot(item);
}
}
}
///<editor-fold defaultstate="collapsed" desc="Tree Item Initialization">
private void initRoot(Object item) {
// Create Menu Items.
MenuItem expandAllMenuItems = new MenuItem("Expand All");
MenuItem collapseAllMenuItems = new MenuItem("Collapse All");
// Event Haddlers for each Menu Items.
expandAllMenuItems.setOnAction(new EventHandler() {
@Override
public void handle(Event event) {
}
});
collapseAllMenuItems.setOnAction(new EventHandler() {
@Override
public void handle(Event event) {
targetTree.collapseChildren();
}
});
// Create Menu and add Menu Items.
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);
//Init Root Tree Item.
String root = (String) item;
setText(root);
setContextMenu(contextMenu);
}
private void initDepartment(Object item) {
// Create Menu Items.
MenuItem expandAllMenuItems = new MenuItem("Expand All");
MenuItem collapseAllMenuItems = new MenuItem("Collapse All");
// Event Haddlers for each Menu Items.
expandAllMenuItems.setOnAction(new EventHandler() {
@Override
public void handle(Event event) {
targetTree.expandChildren();
}
});
collapseAllMenuItems.setOnAction(new EventHandler() {
@Override
public void handle(Event event) {
targetTree.collapseChildren();
}
});
// Create Menu and add Menu Items.
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);
//Init Department Tree Item.
Department department = (Department) item;
setText(department.getName());
setContextMenu(contextMenu);
}
private void initSection(Object item) {
// Create Menu Items.
MenuItem expandAllMenuItems = new MenuItem("Expand All");
MenuItem collapseAllMenuItems = new MenuItem("Collapse All");
// Event Haddlers for each Menu Items.
expandAllMenuItems.setOnAction(new EventHandler() {
@Override
public void handle(Event event) {
targetTree.expandChildren();
}
});
collapseAllMenuItems.setOnAction(new EventHandler() {
@Override
public void handle(Event event) {
targetTree.collapseChildren();
}
});
// Create Menu and add Menu Items.
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);
//Init Section Tree Item.
Section section = (Section) item;
setText(section.getName());
setContextMenu(contextMenu);
}
private void initMeasure(Object item) {
// Create Menu Items.
MenuItem expandAllMenuItems = new MenuItem("Expand");
MenuItem collapseAllMenuItems = new MenuItem("Collapse");
// Event Haddlers for each Menu Items.
expandAllMenuItems.setOnAction(new EventHandler() {
@Override
public void handle(Event event) {
targetTree.expandChildren();
}
});
collapseAllMenuItems.setOnAction(new EventHandler() {
@Override
public void handle(Event event) {
targetTree.collapseChildren();
}
});
// Create Menu and add Menu Items.
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().addAll(expandAllMenuItems, collapseAllMenuItems);
//Init Section Tree Item.
Measure measure = (Measure) item;
setText(measure.getLastname() + " " + measure.getFirstname());
setContextMenu(contextMenu);
}
private void initTarget(Object item) {
//Init Section Tree Item.
Target target = (Target) item;
setText(target.getText());
}
///</editor-fold>
}
如果我有复制粘贴错误,请原谅我..我没有编译问题。该代码正在运行,没有错误。我的问题是关于第一类的方法expandChildren()和crashChildren()。在以前的版本中,我没有使用线程,而是使用递归使所有子项TreeItem(以及它们的子项TreeItem ..)崩溃,但是内存成本更高。
最佳答案
我找到了问题的答案!我将用一个例子来解释。
我用100个TreeItems初始化一个TreeView,结果是一个具有3个级别的树结构。
在屏幕上,树只显示了其中的45个。要查看其他项目,我必须向上/向下滚动或展开折叠的TreeItems。在每种情况下,都会调用方法updateItem来构造新的TreeItem,这些新的TreeItem将在屏幕树上显示为可见,因此它们都出现在屏幕上。
当我折叠展开的TreeItem时,updateItem方法将运行。这就是内存和CPU成本的原因!我不得不折叠〜总共200个TreeItem,然后它们的父级展开了。
我用一种非常简单的方法解决了我的问题。在我开始折叠所有内容之前,我折叠了父级TreeItem。因此,我首先让父母崩溃,然后让所有孩子崩溃。从源代码(setExpanded(false))逐一折叠子项时,由于子项的父项和子项TreeItem在屏幕上不存在,因此updateItem方法未运行。
通过这种方式,我节省了很多内存和CPU时间,这就像我的虚拟人一样。
关于java - 手动扩展/折叠所有treeitems内存成本javafx 2.2,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15490268/