0

我正在使用 JavaFX TreeTableView 来显示销售订单。父行包含“主”记录,子行包含有关订单的信息,包括订购的每个产品的行项目。我正在使用 RowFactory 根据其当前状态突出显示表中的行。RowFactory 的代码以以下代码开头:

        currentOrderTree.setRowFactory(new     Callback<TreeTableView<MmTicket>, TreeTableRow<MmTicket>>() {
            @Override
            public TreeTableRow<MmTicket> call(TreeTableView<MmTicket> p) {
                final TreeTableRow<MmTicket> row = new TreeTableRow<MmTicket>() {
                    @Override
                    protected void updateItem(MmTicket order, boolean empty) {
                        super.updateItem(order, empty);
                        if (order != null) {
                System.out.println("Calling rowFactory method for the " + ++rowcall + " time.");
                            if (packingListPendingList.containsKey(order.getSono())) {
                                if (!getStyleClass().contains("pending")) {
                                    getStyleClass().remove("working");
                                    getStyleClass().remove("fulfilled");
                                    getStyleClass().remove("completed");
                                    getStyleClass().add("pending");
                                    getStyleClass().remove("shipped");
                                }
....

如您所见,每次调用行工厂时,Callback 都会返回一个新的 TreeTableRow。根据 JavaFX 8.0 文档,系统负责管理行的创建,并在适当的时候重用它们。System.out.println 调用记录了该方法被调用的次数。多次上下滚动表格,以及更新销售数据库导致的数据刷新,导致该方法在较短的时间内被调用数万次。随着最终用户广泛使用 TreeTableView,我在程序中的内存使用量继续增长。

分析应用程序表明 HashTable 和 PsuedoClass(我相信 css 的东西)以及诸如 byte[] 和 char[] 和 int[] 之类的东西正在使用非常大量的内存。我尝试了堆大小和垃圾收集器的不同组合,但最终结果总是相同的,因为应用程序最终会耗尽堆空间。

搜索答案表明有些人遇到了这个问题,我发现如果我不做任何行突出显示,从而不调用行工厂,程序在管理内存方面要好得多。任何人都对可能导致此问题的原因或可能的解决方案有任何见解?

4

1 回答 1

1

如果您跟踪正在创建的行对象的数量,您会发现并不多。显然,由于updateItem(...)被调用了这么多次,因此发生了广泛的重用。

需要注意的一件事是它styleClass是作为列表实现的,这当然允许重复。因此,您需要非常小心地管理方法中的内容,例如updateItem(...)当您无法控制何时调用该方法以及将哪些参数传递给它时。具体来说,您可能希望确保没有可能的调用序列updateItem(...)会导致将相同的值多次添加到样式类中。这包括使用order=null. (例如,在您的情况下,如果同一个单元格在用于空单元格、带有order=null和“待定”单元格之间交替使用,会发生什么情况?)看起来您正在通过测试(if (! getStyleClass().contains("pending")))检查这一点,但有一些极端情况可以容易被忽视。

尝试添加getStyleClass().size()到您的调试输出中,看看它是否过度增长。

无论如何,一个更干净的解决方案可能是使用 CSS PseudoClasses 而不是样式类。你可以按照以下方式做一些事情

PseudoClass pending = PseudoClass.getPseudoClass("pending");
PseudoClass working = PseudoClass.getPseudoClass("working");
PseudoClass fulfilled = PseudoClass.getPseudoClass("fulfilled");
PseudoClass completed = PseudoClass.getPseudoClass("completed");
PseudoClass shipped = PseudoClass.getPseudoClass("shipped");


@Override
protected void updateItem(MmTicket order, boolean empty) {
    super.updateItem(order, empty);

    pseudoClassStateChanged(pending, order != null && packingPendingList.containsKey(order.getSono()));
    pseudoClassStateChanged(working, order != null && packingWorkingList.containsKey(order.getSono()));
    pseudoClassStateChanged(fulfilled, order != null && packingFulfilledList.containsKey(order.getSono()));
    pseudoClassStateChanged(completed, order != null && packingCompletedList.containsKey(order.getSono()));
    pseudoClassStateChanged(shipped, order != null && packingShippedList.containsKey(order.getSono()));
}

(或一些适当的逻辑)。PseudoClasses 只有两种状态(设置或未设置),因此这避免了管理样式类列表的所有问题。

在这种情况下,您的 CSS 看起来像

.table-row-cell {
    /* basic styles... */
}

.table-row-cell:pending {
    /* styles specific to pending items */
}

.table-row-cell:working {
    /* styles specific to working items */
}

/* etc etc */

它可能不适用于您的用例,但您也可以将节点与多个 PseudoClasses 设置为

.table-row-cell:pending:working { /* ... */ }

如果您确实想坚持使用样式类,请首先确保您处理 null 情况。你可能想要类似的东西

List<String> allStyles = Arrays.asList("pending", "working", "fulfilled", "completed", "shipped");

@Override
protected void updateItem(MmTicket order, boolean empty) {

    super.updateItem(order, empty);

    if (order == null) {
        getStyleClass().removeAll(allStyles);
    } else {
       // ...
    }
}

而不是

getStyleClass().remove("pending");

删除样式类列表中的第一次出现,考虑"pending"

getStyleClass().removeAll(Collections.singletonList("pending"));

因为该removeAll(Collection)方法删除了提供的集合中包含的所有元素。

updateItem()同样,这可能不是问题的原因,但是如果您在方法中对其进行操作,很容易让样式类列表无限增长。

于 2016-09-12T02:08:57.453 回答