UI更新被javafx中的future.get()阻止 [英] UI updates are getting blocked by future.get() in javafx

查看:153
本文介绍了UI更新被javafx中的future.get()阻止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数应该从Task API的结果中返回一个列表。

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 isSortingQuery {

        try {
            TaskImpl taskImpl = new TaskImpl(isPaginationQuery,
                    isSortingQuery);
            queryExecutor.submit(taskImpl).get();
            return taskImpl.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

执行更新的内部课程

private class TaskImpl extends Task<List> {

        private boolean isPaginationQuery, isSortingQuery;

        public TaskImpl(boolean isPaginationQuery, boolean isSortingQuery) {
            this.isPaginationQuery = isPaginationQuery;
            this.isSortingQuery = isSortingQuery;
        }

        @Override
        protected List call() throws Exception {
             Platform.runLater(() -> {
                  loaderContainer.setVisible(true);
                  loaderContainer.toFront();
             });

            HSession hSession = new HSession();
            TaskInfoDao taskInfoDao = new TaskInfoDaoImpl(hSession.getSession(), currentConnection.getConnectionId());
            if (!isPaginationQuery && !isSortingQuery) {
                paginator.setTotal(taskInfoDao.getTaskInfoWithFiltersCount(paginator.getFilterMap(), false));
            }
            Stream<TaskInfo> resultStream = taskInfoDao.getTaskInfoWithFilters(paginator.getFilterMap(), false,
                    paginator.getStartIndex() * paginator.getPageSize(),
                    paginator.getPageSize() * paginator.getPageGap());
            List<TaskInfoTableView> data = createData(resultStream);
            hSession.close();
            return data;
        }

        @Override
        protected void succeeded() {
            super.succeeded();

            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();
            }
        }

        @Override
        protected void cancelled() {
            super.cancelled();
            updateMessage("Cancelled!");
        }

        @Override
        protected void failed() {
            super.failed();
            updateMessage("Failed!");
        }
    }

performQuery函数调用线程并等待其结果。


使用Platform.runLater从TaskImpl类内部显示加载器。

但是在任务完成之前加载器才会出现,即加载器出现之后完成call()函数的执行。


当我删除taskImpl.get()时,加载程序工作正常。



感谢任何帮助。

performQuery function calls the thread and waits for its result.

The loader is being displayed from inside the TaskImpl class using Platform.runLater.
But the loader does not appear until the task has finished i.e. loader appears after the completion of call() function's execution.

When i remove the taskImpl.get() the loader works fine.

Any help is appreciated.

PS :无论如何,我需要在Inner类之外的Task API的结果(在TaskImpl之外)

P.S. : Under any case, I need the result of the Task API outside the Inner class( outside TaskImpl )

推荐答案

首先,看起来你对异步编程不是很熟悉。让 performQuery()返回列表表明您希望同步运行 - 在获得结果之前,您无法返回结果。这正是你冻结UI的原因。

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.

要理解异步编程的重要一点是,你将开始做某事(即任务)在另一个线程中,并立即返回 。当从任务返回结果时,您切换回UI(JavaFX Application)线程以更新它。您可以将此视为事件驱动方法。

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.

因此,对于您的情况,您应该直接更新列表(您要返回的列表您在 TaskImpl 中覆盖的 succeeded()方法中的performQuery()) class。

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.

如果您要更新的列表不在 TaskImpl 的范围内,那么您可以 java.util.function 包中的功能接口为您完成。这意味着您将在正确的范围内创建该功能接口对象,并在对象构造期间传入 TaskImpl ,并在中调用该接口成功( )

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().

如果我认为这是调用 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());
    }
}

这篇关于UI更新被javafx中的future.get()阻止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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