Search code examples
javaeclipseeclipse-pluginjfacetableviewer

Eclipse plugin: How to add items to a TableViewer asynchronously?


In my Eclipse plugin, I have a TableViewer that shows some data. These data is retrieved from a remote REST service. Therefore it takes some seconds to retrieve all items. That's why I wanted to add items to the TableViewer's ContentProvider as soon as I retrieve them. I do my REST query in a separate thread:

Thread retrieveThread = new RetrieveThread();
retrieveThread.run();

In this thread I add items to my TableViewer:

MyView.instance.addItems(items);

And the same method in the class MyView:

public void addItems(List<Result> items) {
    ModelProvider.INSTANCE.addItems(items);
    resultLabel.setText(ModelProvider.INSTANCE.getItems().size() + " items");
    PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {

        @Override
        public void run() {
            viewer.refresh();
        }
    });
}

I expected that this procedure will add items to my TableViewer and then refresh the view. But what happens now is that my Eclipse freezes and adds all them items at the same time. How can I do this in a more responsive way?


Solution

  • The issue is that you are calling the run method of your thread directly. This does not spawn a new thread, it just calls the run method in-line. retrieveThread.start() would give you the behaviour you are looking for.

    However, there is a better way of doing it (at least more 'eclipse friendly'), and that is to use an Eclipse Job instead of a raw Thread.

        Job retrieveJob = new Job("Retrieving Data") 
        {           
            @Override
            protected IStatus run(IProgressMonitor monitor) {
                // do your REST call
                ModelProvider.INSTANCE.addItems(items);
                // if something goes wrong - don't return ok, obviously 
                return Status.OK_STATUS;                
            }
        };
        retrieveJob.addJobChangeListener(new JobChangeAdapter() {
    
            @Override
            public void done(IJobChangeEvent event) {
                if(event.getResult().isOK())
                {
                    resultLabel.setText(ModelProvider.INSTANCE.getItems().size() + " items");
                    viewer.refresh();
                }
            }           
        });
        // this will run in a background thread 
        // and nicely integrate with the UI
        retrieveJob.schedule();