JavaFX ListCell Performance

lam_tr

Top Contributor
Hallo zusammen,

irgendwie habe ich aktuell ein Problem dass die Darstellung von einer ListView mit Custom ListCell sehr lange dauert. Warum ist das so? Ich habe versucht alle Instantieren aus der ListCell rauszunehmen, aber merke doch dass die Erstellung von ca 100 Einträge relativ lange dauert ca. 2Minunten.

Hier habe ich ein Beispiel meiner Anwendung

Code:
import java.io.IOException;
import java.text.DecimalFormat;
import javafx.beans.property.ObjectProperty;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.ListCell;
import javafx.scene.input.ClipboardContent;

public class AgileListViewCells extends ListCell<Ticket>{

    ObjectProperty<ListCell<Ticket>> dragSource;

    static FXMLLoader mLLoader;
    static DecimalFormat df = new DecimalFormat( "00000");
    static ClipboardContent cc = new ClipboardContent();
   
    private Node content;
    private AgileListViewCellController controller;
   
    public AgileListViewCells(ObjectProperty<ListCell<Ticket>> dragSource){
        this.dragSource=dragSource;
        mLLoader = new FXMLLoader(getClass().getResource("/de/dm/ui/AgileListViewCell.fxml"));
        this.controller = mLLoader.getController();
        try {
            content = mLLoader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
   
    @Override
    protected void updateItem(Ticket item, boolean empty) {
        super.updateItem(item, empty);
        if (empty || item == null) {
            setText(null);
            setGraphic(null);
        }else {
            if (controller==null) {
                this.controller = mLLoader.getController();
            }
            controller.update(item, content);
            controller.updateStatus(item);
            setText(null);
            setGraphic(content);
        }
    }
}
[code]

Hier der passende Controller dazu, sorry ich hoffe der Code (Xtend) unten ist verständlich, da ich nicht noch in reines Java konvertieren kann:
[code]
class AgileListViewCellController extends BaseAgileListViewCellController {
   
    static Image STATUS = new Image(new File("resource/icons/status-icon.png").toURI.toString)
    static Image BUSY =  new Image(new File("resource/icons/status-busy-icon.png").toURI.toString)
    static Image AWAY =  new Image(new File("resource/icons/status-away-icon.png").toURI.toString)
    static Image OFFLINE =  new Image(new File("resource/icons/status-offline-icon.png").toURI.toString)
   
    static DecimalFormat df = new DecimalFormat( "00000")
   
    def void updateStatus(Ticket item) {
        titleText.strikethrough = item.status.strikethrough
        statusPanel.style = item.status.style
        var image = STATUS
        if (item.status == Status.Open) {
            image = BUSY
        } else if (item.status == Status.Waited) {
            image = AWAY
        } else if (item.status == Status.Closed) {
            image = OFFLINE
        }
        statusImage.image = image
    }
   
    def void update(Ticket item, Node node){
        val first = AppConfig.Instance.projectDao.cachedEntries.findFirst[it.id==item.project]
        projectLink.text = first.shortName
        idLink.text = df.format(item.id)
        titleText.text = '''«item.name»'''
        item.updateStatus
        priorityImage.image = Type.getImage(item.type)
        Tooltip.install(priorityImage, new Tooltip(Type.getType(item.type).niceName))
        Tooltip.install(node, new Tooltip('''
        Id:             «item.id»
        Title:            «item.name»
        Status:        «item.status.niceName»
        Priority:        «Type.getType(item.type)»
        Description:    «item.description»
        '''))
    }
}}
[code]

Hat da jemand eine Idee, warum das rendern jeder einzelenen ListCell so viel Zeit beansprucht.

Grüße
lam
 
Hast du mal nen Profiler benutzt und geguckt, wo so viel Zeit verbraucht wird?

Spontan würde ich auf das Laden aus der fxml Tippen, ist aber nur Spekulation.
 
Das komische ist wenn ich über Eclipse laufen lasse, ist es etwas flüssiger, also im Sekundenbereich dann fertig, aber als Jar dauert dass irgendwie 2 Minuten. merkwürdig.
 
Hallo mrBrown,

ich glaube das ist vernachlässigbar, aber immer 3 so ein Block ergibt eine 1 Sekunde, und aktuell stelle ich 150 Items da, d.h. der braucht 50 Sekunden bis alles gerendert ist.

*** ITEMS BEGIN ******************************************************
2017-06-24T15:44:36.965Z: Get Resource, AgileListViewCells
2017-06-24T15:44:36.965Z: Resource loaded, AgileListViewCells
2017-06-24T15:44:36.965Z: FXML finished, AgileListViewCells
2017-06-24T15:44:36.966Z: Get Controller
2017-06-24T15:44:37.236Z: FXML Node loaded finished, AgileListViewCells
2017-06-24T15:44:37.236Z: Construtcot end, AgileListViewCells
2017-06-24T15:44:37.236Z: Update begin, AgileListViewCells
2017-06-24T15:44:37.236Z: Update end, AgileListViewCells
*** ITEM END *********************************************************

Ich kenne mich mit dem Profiling nicht aus deswegen habe ich Sysout reingebaut.

Grüße
lam
 
Also aus der Hüfte geschossen, dauert das initialisieren deiner GUI (AgileListViewCell.fxml) und des damit Controllers so lange (der Controller wird bei mLLoader.load() auf jeden Fall erstellt und initialisert, egal, ob du mLLoader.getController aufrufst, oder nicht).
Wie sieht das FXML und der Controller denn aus? Code?
 
Hallo dzim,

die FXML ist wie folgt aufgebaut

Code:
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" 
minWidth="-Infinity" prefHeight="70.0" prefWidth="250.0" 
style="-fx-border-color: whitesmoke; -fx-background-color: white;" 
stylesheets="@/de/ui/AgileListViewCell.css" xmlns="http://javafx.com/javafx/8" 
xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.dc.controller.AgileListViewCellController"> 
    <children>
        <ImageView fx:id="statusImage" fitHeight="20.0" fitWidth="20.0" layoutX="2.0" layoutY="2.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="2.0" />
        <ImageView fx:id="priorityImage" fitHeight="15.0" fitWidth="15.0" layoutX="2.0" layoutY="30.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="12.0" AnchorPane.topAnchor="25.0" />
        <ImageView fitHeight="25.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true" AnchorPane.rightAnchor="2.0" AnchorPane.topAnchor="2.0">
            <image>
                <Image url="@/icons/useravatar.png" />
            </image>
        </ImageView>
        <AnchorPane fx:id="statusPanel" prefWidth="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
        <HBox layoutX="30.0" layoutY="3.0">
            <children>
                <Hyperlink fx:id="projectLink" alignment="CENTER_RIGHT" layoutX="30.0" layoutY="7.0" text="NAM" AnchorPane.topAnchor="2.0" />
                <Hyperlink fx:id="idLink2" alignment="CENTER_RIGHT" prefHeight="23.0" prefWidth="1.0" text="-" />
                <Hyperlink fx:id="idLink" text="00000" />
            </children>
        </HBox>
        <Text fx:id="titleText" layoutX="36.0" layoutY="34.94921875" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" wrappingWidth="210.13671875" AnchorPane.leftAnchor="32.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="25.0">
            <font>
                <Font name="System Italic" size="12.0" />
            </font>
        </Text>
    </children>
</AnchorPane>
[code]

Der Controller wurde im ersten Post im Code Box unten aufgelistet.
An sich ist die FXML nicht mal so kompliziert verschachtelt oder aufgebaut, aber die ganen ImageDateien fressen vermutlich viel Speicher bei der Instanzierung.
Grüße
lam
 
UU wird das Image mehrmals geladen, ich weiß nicht wie JavaFx da intern arbeitet - das könnte man lösen, wenn man die Abhängigkeit aus der fxml nimmt und sie intern cached.

Ansonsten könnte vllt das reine Laden der Datei das langsame sein.
 

Zurück
Oben