我正在使用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/

10-12 03:41