Running a background task from an annotator

Hi everyone,

I have a proble with an annotator which is used to type check the current file. The first time the annotator is used, it retrieves a global type checker which can then be reused for later usage. The problem is, instantiating this type checker can take some time, depending on the project size. IIUC, the IDE waits for this annotator to finish because the UI is frozen during the type checker's instantiation (on a real project it can take up to 25s). To circumvent this, I'd like the type checker to be instantiated in a background thread (with a progress indicating something is loading to the user), return immediatly from the annotator, and restart the annotator once the type checker is ready.

Here's my current attempt (extracted from a projectService extension):

    private TypeChecker typeChecker;
    private boolean isBuildingTypeChecker = false;


    public TypeChecker getTypeChecker() {         if (typeChecker == null && !isBuildingTypeChecker) {             isBuildingTypeChecker = true; // TODO really thread-safe?             Runnable instantiateTypeCheckerTask = new Runnable() {                 @Override                 public void run() {                     typeChecker = createTypeChecker();                     isBuildingTypeChecker = false;                     DaemonCodeAnalyzer.getInstance(project).restart();                 }             };             RunnableBackgroundableWrapper taskWrapper = new RunnableBackgroundableWrapper(project, "Preparing Ceylon project", instantiateTypeCheckerTask);             ProgressIndicator progressIndicator = new BackgroundableProcessIndicator(taskWrapper);             progressIndicator.setIndeterminate(true);             progressIndicator.setText("Preparing Ceylon project...");             // We still get a (harmless?) error :(             ProgressManager.getInstance().runProcessWithProgressAsynchronously(taskWrapper, progressIndicator);         }         return typeChecker;     }


Calling runProcessWithProgressAsynchronously() displays an error telling me that I should call it from the EDT ("Access is allowed from event dispatch thread only."). The debugger also tells me that I'm in a different thread. While I'm aware this message is harmless, I'd still like to avoid it.

1. How come the UI freezes if I don't run the code in a background thread, whereas the annotator is not run from the EDT/UI thread?
2. Is there another API that I missed which would allow me to run a background task, with progress, that must not be run from the EDT?

Thanks for your help

5 comments

Here is the general idea of how to run a backroundable task

ProgressManager.getInstance().run(new Backgroundable(project, "Description") {
            @Override
            public void run(@NotNull final ProgressIndicator progressIndicator) {


                // put your code here
                                // to access Project use myProject field
            }
        });

0

Thanks for the hint, but I still get the same (hamrless?) error, although it does not stop my task:

19:17:10 Throwable          Access is allowed from event dispatch thread only.          Details: Current thread: Thread[JobScheduler FJ pool 3/4,6,main] 495027284          Our dispatch thread:Thread[AWT-EventQueue-0 13.0#IU-133.124, eap:true,6,main] 1803322541          SystemEventQueueThread: Thread[AWT-EventQueue-0 13.0#IU-133.124, eap:true,6,main] 1803322541


I guess there's no workaround to this?

0

try to enclose the code that access the UI into WriteAction, check this workaround

ApplicationManager.getApplication().invokeLater(new Runnable() {
            public void run() {
                ApplicationManager.getApplication().runWriteAction(new Runnable() {
                    @Override
                    public void run() {


                       // Access UI here
                    }
                });
            }
        });

0

Thanks Mahmoud, it seems to be working with the following code:

            ApplicationManager.getApplication().invokeLater(new Runnable() {                 @Override                 public void run() {                     ProgressManager.getInstance().run(new Task.Backgroundable(project, "Preparing Ceylon project...") {                         @Override                         public void run(@NotNull ProgressIndicator indicator) {
                              // my background task here                         }                     });                 }             });

0

WriteAction is required to guard modifications (of PSI or document text or VFS or ...).
For mere UI refresh invokeLater suits better.

0

Please sign in to leave a comment.