UI updates are getting blocked by future.get() in javafx

后端 未结 1 1055
礼貌的吻别
礼貌的吻别 2021-01-28 07:15

I have a function which is supposed to return a list from the result of a Task API.

    @Override
    public List performQuery(boolean isPaginationQuery, boolean         


        
相关标签:
1条回答
  • 2021-01-28 07:53

    First of all, it seems like you are not very familiar with asynchronous programming. Having performQuery() to return a List shows that you are expecting to run this synchronously - there is no way for you to return results before you get the results. This is exactly why you are freezing your UI.

    The important thing to understand about asynchronous programming is, you would start doing something (i.e. a task) in another thread, and return immediately. When there is result returned from the task, you switch back to the UI (JavaFX Application) thread to update it. You can see this as event-driven approach.

    Therefore, for your case, you should directly update the list (the list which you are returning in performQuery()) in the succeeded() method that you have overridden in TaskImpl class.

    If the list that you should be updating is not in the scope of TaskImpl, then you can the functional interfaces in java.util.function package to do it for you. This means that you would create that functional interface object at the right scope, and pass in into TaskImpl during object construction, and call that interface in succeeded().

    Update

    If I assume this is what calls performQuery():

    public class MyController {
        @FXML
        TableView<Foo> tableView;
    
        public void initialize() {
            List result = queryController.performQuery(true, true);
            tableView.getItems().addAll(result);
        }
    }
    

    Then, I would probably do something like this:

    public class MyController {
        @FXML
        TableView<Foo> tableView;
    
        public void initialize() {
            List result = queryController.performQuery(true, true, list -> tableView.getItems.addAll(list));
        }
    }
    
    public class QueryController {
        @Override
        public void performQuery(boolean isPaginationQuery, boolean isSortingQuery, java.util.function.Consumer<List> onQuerySucceeded) {
    
            try {
                TaskImpl taskImpl = new TaskImpl(isPaginationQuery,
                        isSortingQuery, onQuerySucceeded);
    
                queryExecutor.submit(taskImpl);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    private class TaskImpl extends Task<List> {
    
        private final java.util.function.Consumer<List> onQuerySucceeded;
    
        public TaskImpl(boolean isPaginationQuery, boolean isSortingQuery, java.util.function.Consumer<List> onQuerySucceeded) {
            this.isPaginationQuery = isPaginationQuery;
            this.isSortingQuery = isSortingQuery;
    
            this.onQuerySucceeded = onQuerySucceeded;
        }
    
        @Override
        protected void succeeded() {
            super.succeeded();
    
            // Not sure what the original codes are doing.
            try {
                //set the pagination if the task is complete
                //and it is not a pagination query
                if (!isPaginationQuery) {
                    ((TaskInfoViewController) uiController).setPagination(
                            FXCollections.observableArrayList(get()));
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
    
            // This is what is being added in
            onQuerySucceeded.accept(this.getValue());
        }
    }
    
    0 讨论(0)
提交回复
热议问题