延迟加载FXProperties [英] Lazy-loading FXProperties

查看:133
本文介绍了延迟加载FXProperties的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是



要重现,请在表格中快速向下滚动应用程序。有些单元格不显示延迟加载值,而是占位符字符串。



延迟加载属性如下所示:

 公共抽象类LazyLoadingStringProperty扩展SimpleStringProperty {

public static final String DEFAULT_LOADING_STRING =Loading ..;
private static final ExecutorService exe = Executors.newCachedThreadPool();
private String loadingString = DEFAULT_LOADING_STRING;

private boolean loaded = false;

public LazyLoadingStringProperty(){

}

public boolean isLoaded(){
return loaded;
}

public void setLoaded(final boolean loaded){
this.loaded = loaded;
}

public String getLoadingString(){
return loadingString;
}

public void setLoadingString(final String loadingString){
this.loadingString = loadingString;
}

@Override
public String getValue(){
if(!loaded){
Platform.runLater(() - > startLoadingService( ));
返回loadingString;
}
返回super.getValue();
}

protected void startLoadingService(){

final service< String> s = new Service< String>(){

@Override
protected Task< String> createTask(){
return LazyLoadingStringProperty.this.createTask();
}
};

s.setExecutor(exe);

s.setOnFailed(e - > {
setLoaded(true);
setValue(s.getException()。getLocalizedMessage());

});

s.setOnSucceeded(e - > {
setLoaded(true);
setValue(s.getValue());

});
s.start();
// System.err.println(已开始);
}

protected abstract任务< String>的CreateTask();

}



Applikation看起来像这样:

  public class ExampleTable extends Application {

private static final int NUM_ELEMENTS = 500;

private final TableView< ExampleBean> table = new TableView<>();

private final ObservableList< ExampleBean> data = FXCollections.observableArrayList();

public static void main(final String [] args){
launch(args);
}

@Override
public void start(最后阶段阶段){
final Scene scene = new Scene(new Group());
stage.setTitle(表格视图示例);
stage.setWidth(300);
stage.setHeight(500);

final TableColumn< ExampleBean,String> c1 = new TableColumn<>(A);
c1.setCellValueFactory(new PropertyValueFactory< ExampleBean,String>(p1));
final TableColumn< ExampleBean,String> c2 = new TableColumn<>(B);
c2.setCellValueFactory(new PropertyValueFactory< ExampleBean,String>(p2));
final TableColumn< ExampleBean,String> c3 = new TableColumn<>(C);
c3.setCellValueFactory(new PropertyValueFactory< ExampleBean,String>(p3));

c1.setPrefWidth(100);
c2.setPrefWidth(100);
c3.setPrefWidth(100);


for(int i = 0; i< NUM_ELEMENTS; i ++){
data.add(new ExampleBean());
}

final ScrollPane sp = new ScrollPane();
sp.setContent(table);
sp.setMaxHeight(Double.POSITIVE_INFINITY);
sp.setMaxWidth(Double.POSITIVE_INFINITY);
sp.setFitToHeight(true);
sp.setFitToWidth(true);

table.setItems(data);
// table.setMaxHeight(Double.POSITIVE_INFINITY);
// table.setMaxWidth(Double.POSITIVE_INFINITY);
table.getColumns()。addAll(c1,c2,c3);

final VBox vbox = new VBox();
vbox.setSpacing(5);
VBox.setVgrow(sp,Priority.ALWAYS);
vbox.getChildren()。addAll(sp);

scene.setRoot(vbox);


stage.setScene(scene);
stage.show();
}
}

可以找到完整的可运行代码这里

解决方案

它看起来像JavaFX服务中的一个错误...



因为没有保存对服务它们被垃圾收集的实例。

有时它们中的一些在任务完成之前被垃圾收集。

在这种情况下,<$ b $的监听器c $ c> onFailed 和 onSucceeded 未调用服务的属性。



简单的解决方案是使用 LazyLoadingStringProperty 对象保存服务引用:

 。 .. 
private ArrayList< Service< String>> services = new ArrayList<>();

protected void startLoadingService(){

final service< String> s = new Service< String>(){
@Override
protected Task< String> createTask(){
return LazyLoadingStringProperty.this.createTask();
}
};
services.add(s);
...

但是不需要并行加载一个具有多个任务的值。
因此,每个值的一项服务绰绰有余:

  ... 

private服务与LT;字符串> S;

protected void startLoadingService(){

if(s!= null)return; //已经开始

s =新服务< String>(){
...


This is a follow-up from here.

I am implementing a table, that loads data asynchronously into the table cells. The problem is, that the table cells sometimes do not update correctly. Sometimes it somehow 'hangs' and shows "Loading.." forever. The actual value updates only when I scroll in the table a little bit.

To reproduce, run the application an scroll down fast in the table. Some cells will not show the 'lazily-loaded' value but the placeholder string.

The lazy-loading property looks like this:

public abstract class LazyLoadingStringProperty extends SimpleStringProperty {

public static final String DEFAULT_LOADING_STRING = "Loading..";
private static final ExecutorService exe = Executors.newCachedThreadPool();
private String loadingString = DEFAULT_LOADING_STRING;

private boolean loaded = false;

public LazyLoadingStringProperty() {

}

public boolean isLoaded() {
    return loaded;
}

public void setLoaded(final boolean loaded) {
    this.loaded = loaded;
}

public String getLoadingString() {
    return loadingString;
}

public void setLoadingString(final String loadingString) {
    this.loadingString = loadingString;
}

@Override
public String getValue() {
    if (!loaded) {
        Platform.runLater(() -> startLoadingService());
        return loadingString;
    }
    return super.getValue();
}

protected void startLoadingService() {

    final Service<String> s = new Service<String>() {

        @Override
        protected Task<String> createTask() {
            return LazyLoadingStringProperty.this.createTask();
        }
    };

    s.setExecutor(exe);

    s.setOnFailed(e -> {
        setLoaded(true);
        setValue(s.getException().getLocalizedMessage());

    });

    s.setOnSucceeded(e -> {
        setLoaded(true);
        setValue(s.getValue());

    });
    s.start();
    // System.err.println("Started");
}

protected abstract Task<String> createTask();

}

The Applikation looks like this:

public class ExampleTable extends Application {

    private static final int NUM_ELEMENTS = 500;

    private final TableView<ExampleBean> table = new TableView<>();

    private final ObservableList<ExampleBean> data = FXCollections.observableArrayList();

    public static void main(final String[] args) {
        launch(args);
    }

    @Override
    public void start(final Stage stage) {
        final Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(300);
        stage.setHeight(500);

        final TableColumn<ExampleBean, String> c1 = new TableColumn<>("A");
        c1.setCellValueFactory(new PropertyValueFactory<ExampleBean, String>("p1"));
        final TableColumn<ExampleBean, String> c2 = new TableColumn<>("B");
        c2.setCellValueFactory(new PropertyValueFactory<ExampleBean, String>("p2"));
        final TableColumn<ExampleBean, String> c3 = new TableColumn<>("C");
        c3.setCellValueFactory(new PropertyValueFactory<ExampleBean, String>("p3"));

        c1.setPrefWidth(100);
        c2.setPrefWidth(100);
        c3.setPrefWidth(100);


        for (int i = 0; i < NUM_ELEMENTS; i++) {
            data.add(new ExampleBean());
        }

        final ScrollPane sp = new ScrollPane();
        sp.setContent(table);
        sp.setMaxHeight(Double.POSITIVE_INFINITY);
        sp.setMaxWidth(Double.POSITIVE_INFINITY);
        sp.setFitToHeight(true);
        sp.setFitToWidth(true);

        table.setItems(data);
        // table.setMaxHeight(Double.POSITIVE_INFINITY);
        // table.setMaxWidth(Double.POSITIVE_INFINITY);
        table.getColumns().addAll(c1, c2, c3);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        VBox.setVgrow(sp, Priority.ALWAYS);
        vbox.getChildren().addAll(sp);

        scene.setRoot(vbox);


        stage.setScene(scene);
        stage.show();
    }
}

The complete runnable code can be found here.

解决方案

It looks like a bug in JavaFX Service ...

As there are no saved references to Service instances they are garbage collected.
And sometimes some of them are garbage collected before their tasks are finished.
In this case listeners of onFailed and onSucceeded properties of a service are not called.

The simple resolution is to save services references with LazyLoadingStringProperty object:

...
private ArrayList<Service<String>> services = new ArrayList<>();

protected void startLoadingService() {

    final Service<String> s = new Service<String>() {
        @Override
        protected Task<String> createTask() {
            return LazyLoadingStringProperty.this.createTask();
        }
    };
    services.add(s);
    ...

But there is no need to load one value with many tasks in parallel. So one service per value is more than enough:

    ...

    private Service<String> s;

    protected void startLoadingService() {

        if (s != null) return; // started already

        s = new Service<String>() {
            ...

这篇关于延迟加载FXProperties的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆