How to run a Backgroundable Task in progress and synchronously?
Hello,
what I am trying to achieve:
Run multiple tasks in a background threads, but synchronously with order each after the other.
I have tried to search the forum for the answer, but still have an open question.
Assuming code like this:
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
public void run() {
ProgressManager.getInstance().runProcessWithProgressSynchronously(
myRunnable, "Running my task", true, project
);
}
}, ModalityState.NON_MODAL);
// this line is executed after myRunnable is finished
Good about this I can cancel the running task, bad is, you cannot move it to background and the ui is blocked from doing any actions.
I tried to change this code to:
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
public void run() {
BackgroundableWrapper backgroundableWrapper = new BackgroundableWrapper(project, "Running my task", myRunnable);
ProgressManager.getInstance().run(backgroundableWrapper);
}
}, ModalityState.NON_MODAL);
// this line is run in a non blocking way, without waiting for background task to complete. In my case it is bad.
// where BackgroundableWrapper is similar to RunnableBackgroundableWrapper:
public class BackgroundableWrapper extends Task.Backgroundable { private final Runnable task; public BackgroundableWrapper(@Nullable Project project, @NotNull String title, Runnable task) { super(project, title, true, PerformInBackgroundOption.DEAF); this.task = task; } public void run(@NotNull ProgressIndicator indicator) { task.run(); } }
Good now is the task is cancable and backgroundable, bad is it is running async without waiting.
How can I do a cancable backgroundable task running in a "runProcessWithProgressSynchronously" mode?
Thank you!
Please sign in to leave a comment.
By definition, background tasks can't be run synchronously (because otherwise, the event dispatch thread would be locked waiting for the background task to complete, the user would not be able to perform any other actions, and the "background" operation would not run in background at all). What you need to do is, when your background operation completes, use invokeLater() to transfer the control back to the event dispatch thread to start the next step of the operation.
My problem is what supposed to be happen in Application.getApplication().invokeLater(new Runnable() {... }) after task is done is not under my control. To be more precise,
I run inside GlobalInspectionContextExtension#performPreRunActivities a long running task
After performPreRunActivities is done IDEA executes the inspections.
Now because all tasks are backgroundable, performPreRunActivities is done before they are finished, then inspections are executed, but do nothing, because they need the results from the tasks.
I need to tell the inspections context to execute first if tasks are done.
If transforming this issue to .NET I need something like
Results results =await myTask;
If you like to see the full source code: https://github.com/sonar-intellij-plugin/sonar-intellij-plugin/blob/master/src/main/java/org/intellij/sonar/analysis/SonarQubeInspectionContext.java
The performPreRunActivities() method is already called under a progress indicator; you can't (and shouldn't) create any additional progress indicators inside your own code.
ok, following your instructions:
update:
now it works, it is simpler as I don't need to care about tasks at all.
IntelliJ is already wrapping it into a backgroundable task :-)