Lazy-loading items in TableView

梦想与她 提交于 2020-01-01 22:15:23

问题


I am implementing a custom TableCellFactory to load data asynchronously from a database. Querying the db should not block the UI thread.

public abstract class AsynchronousTableCellFactory<E, T> implements Callback<TableColumn<E, T>, TableCell<E, T>> {

private static final Executor exe1 = Executors.newFixedThreadPool(2);

private static final Executor exe2 = Executors.newFixedThreadPool(2);

@Override
public TableCell<E, T> call(final TableColumn<E, T> param) {
    final TableCell<E, T> cell = new TableCell<E, T>() {

        @Override
        public void updateItem(final T item, final boolean empty) {

            super.updateItem(item, empty);

            if (empty) {
                setText(null);
            } else {
                setText("Thinking..");
                // do this later some time, we need to finish here FAST
                exe1.execute(() -> {

                    if (getTableRow() != null) {
                        final Service<T> service = new Service<T>() {

                            @Override
                            protected Task<T> createTask() {
                                return getTask((E) getTableRow().getItem());
                            }
                        };
                        service.setExecutor(exe2);
                        service.setOnSucceeded(e -> {

                            if (e.getSource().getValue() == null) {
                                setText("n/a");
                            } else {
                                setText(e.getSource().getValue().toString());
                            }

                        });
                        service.setOnFailed(e -> {
                            final Throwable t = e.getSource().getException();
                            setText(t.getLocalizedMessage());
                        });
                        service.start();
                    }
                });
            }
        }
    };

    return cell;
}

protected abstract Task<T> getTask(E rowDataItem);

}

It is working most of the time, but not always. One strange thing about it is that T item is always null. In which cases can I expect T item to be null?

The corresponding table code:

public class OriginsTableViewController implements Initializable {

@FXML
private TableView<LazyLoadingOriginWrapper> table;
@FXML
private TableColumn<LazyLoadingOriginWrapper, String> cSampleName;

@Override
public void initialize(final URL location, final ResourceBundle resources) {
    cSampleName.setCellFactory(new AsynchronousOriginTableCellFactory<>(e -> e.getSampleName()));

}

EDIT: Find the better approach here.


回答1:


Be aware that a TableCell is reusable! this means any item can be assigned to any cell (that's what the updateItem method is for). Your current code can provide a lot of problems as your completion handlers set a TableCell's text directly.

An easy solution is wrapping the result in a ObservableValue inside your LazyLoadingOriginWrapper and use that in a CellValueFactory rather than creating your own TableCell. Updates of the ObservableValue will be vissible inside the TableView (make sure you modify the ObservableValue on the 'fx-application' thread!). e.g.

public static class LazyLoadingOriginWrapper
{
    // params are 'bean', 'id/name', 'default value'
    ObservableStringValue name = new SimpleStringProperty(this, "name", "thinking...");

    public ObservableStringValue nameProperty() { return name; }

    public void setName(String value)
    {
         Platform.runLater(() -> name.set(value));
     }

    // add your logic for asynchronious loading here and update the above ObservableValue instead. Make sure you trigger it manually!
}

@Override
public void initialize(final URL location, final ResourceBundle resources) {
    cSampleName.setCellValueFactory(C -> C.getValue().nameProperty());
}


来源:https://stackoverflow.com/questions/48962796/lazy-loading-items-in-tableview

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!