0

I have a SwingWorker class whose doInBackground executes queries on a remote database. I invoke publish(true) which sets setVisible to true for the JDialog holding a loader animation.

Everything is working fine as expected:

  1. Background method starts.
  2. JDialog modal is shown.
  3. Background method completes.
  4. JDialog is hidden/disposed in done() method.
  5. UI is updated with database values.

However, when I point my application to the database running on my local machine the JDialog is shown but never closed/disposed even though the done() was called. This halts execution of UI code in the done method as well not until I manually close the loader dialog.

This odd behaviour is as follows:

  1. Background method starts.
  2. JDialog modal is shown.
  3. Background method completes.
  4. JDialog is NOT hidden/disposed in done() method.
  5. UI is NOT updated

I must mention that execution over the remote database takes 10 seconds or more but a split second on my local database. How is the faster speed causing this odd behaviour?

Below is my code snippet:

    new SwingWorker<Void, Boolean>() {
        JDialog loader = new MyDialogLoader();

        @Override
        protected Void doInBackground() {
            publish(true);
    
            //DATABASE EXECUTION CODE IS HERE

            publish(false);
            return null;
        }

        @Override
        protected void process(List<Boolean> chunks) {
            for (Boolean val : chunks) {
                loader.setVisible(val);
            }
        }

        @Override
        protected void done() {
            loader.dispose();
            //UI UPDATE WITH DATABASE VALUES CODE HERE;
        }
    }.execute();
Salim JB
  • 41
  • 4
  • 1
    Can you post a [mre]? – gthanop Jul 10 '21 at 21:15
  • I wouldn't use publish and process for this purpose but rather a PropertyChangeListener – Hovercraft Full Of Eels Jul 10 '21 at 21:22
  • @gthanop It's really just that piece of code other than the JDBC code left out. – Salim JB Jul 10 '21 at 21:30
  • @HovercraftFullOfEels Thanks. I will try implementing using PropertyChangeListener and provide feedback. – Salim JB Jul 10 '21 at 21:31
  • @user16320675 Thanks. I will give that a try too. – Salim JB Jul 10 '21 at 21:32
  • @gthanop the `SwingWorker` is implemented as an anonymous class inside `onClick` event of a button. But I get your point on the need of a reprex unfortunately, there is not much to to add to the code really. In a nuthsell the JDialog is not closing when targeting a local database but works as expected when I point to a remote (much much slower connection) database. – Salim JB Jul 10 '21 at 21:50
  • 1
    @Salim JB [maybe, you would need to fit with your issue](https://stackoverflow.com/q/7053865/714968) – mKorbel Jul 12 '21 at 13:41

2 Answers2

1

Probably there is an Exception being thrown in doBackground(), so publish(false) is not being executed. Maybe an error accessing the database...

The Exceptions thrown by doBackground are silently caught and saved by the SwingWorker. The way to check if such an Exception was thrown, is to call the get() method in the done() method. It will throw an ExecutionException having the original exception as cause:

    @Override
    protected void done() {
        loader.dispose();
        try {
            get();
        } catch (ExecutionException ex) {
            ex.printStackTrace();
            // some message or what ever using ex.getCause()
        } catch (InterruptedException ex) {
            ex.printStackTrace();
            // TODO
        }

        //UI UPDATE WITH DATABASE VALUES CODE HERE;
    }
user16320675
  • 135
  • 1
  • 3
  • 9
  • No exceptions were thrown even after calling `get()` -- very odd. I've shared something that seems to have worked. Thanks. – Salim JB Jul 11 '21 at 00:31
0

I am sharing this as the answer because it has solved the issue.

I did away with publish and process methods; the loader JDialog is now made visible from doInBackground. To ensure this UI interaction is performed on the Event Dispatch Thread, the statement is placed inside SwingUtilities.invokeLater.

new SwingWorker<Void, Void>() {
        JDialog loader = new MyDialogLoader();
        @Override
        protected Void doInBackground() {
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            try {
                                loader.setVisible(true);
                            } catch (Exception e) {
                                e.printStackTrace()
                            }
                        }
                    });
    
            //DATABASE EXECUTION CODE IS HERE

            return null;
        }

        @Override
        protected void done() {
            loader.dispose();
            //UI UPDATE WITH DATABASE VALUES CODE HERE;
        }
    }.execute();
Salim JB
  • 41
  • 4