1

I use a class extending SwingWorker that looks as follows:

public class Analyzer extends SwingWorker<Integer, Object> {

  String source;
  public Analyzer(String simulation, DBConnector connection)
        throws ClassNotFoundException, SQLException, IOException {
    super();
    source=simulation;

    //creating several objects that get their data from a DB and will be "analyzed" in the background
  }

  @Override
  protected Integer doInBackground() {

    tripAnalyzer ta = new tripAnalyzer();
    if (trips.getIterator().hasNext()) {

        if (isCancelled()) {
            trips.close();
            ta.cancelFinish();
            return FAILED;
        }

        ta.init(null, null, false);

        while (trips.getIterator().hasNext()) {

            setProgress(trips.getProgress());
            ta.prepare(source, trips.getIterator().next());
        }
        //export the results to a text-file
        return SUCCESS;
    }    
  }
  @Override
  protected void done() {
    setProgress(100);
    trips.close();
    super.done();
  }
}

The simulation String value comes from a JTable. So far it all works fine for one "simulation key" but now I want to expand this to be able to do the Worker stuff for several "simulation keys". One approach I thought of could be to pass an array or list of Strings with simulation keys and change the constructor appropriately. But that would become utterly clumpy as I would have to create lots of objects during the execution of the constructor and there is A LOT of data to be processed. I could also create a separate constructor specifically for an array of Strings but that would be copy/paste of approx 60 lines of code and there would be the issue of clumpiness.

My idea was to reinstantiate the Analyzer class with a different simulation key when analysis on a previous simulation was done. (yes I know instantiating the same SwingWorker several times during EDT does not invoke the doInBackground method more than once. But once it's done and off the hook it should work... in my head at least :)). But right now I hit a wall and don't really know how to proceed.

The workflow should be like this:

1: I choose f.ex. 3 simulation keys from a JTable stored in an array or list [1,2,3]

2: then the Worker gets instantiated from my GUI-class and does his work on the first key i.e. '1'

3: after work on '1' is done the worker should be reinstantiated and start working on '2'

4: and so on until all simulation keys have been processed.

Maybe my thinking is too stiff and there are better ways to accomplish this therefore any help at all to point me in the right direction will be greatly appreciated! Thanks

EDIT

public Analyzer(String simulation, DBConnector connection){

    this(new String[]{simulation}, connection);
    source = simulation;
}

public Analyzer(String[] simulation, DBConnector connection){

    super();
    for( String s : simulation) this.simulations.add(s);
    this.connection = connection;
}

As mentioned in the comments below the publish() method wasn't needed as the statusbar updates correctly.

The list where I put all the keys is a LinkedList that gets stripped of a key during every loop cycle until it is empty.

motaa
  • 327
  • 2
  • 11
  • Why not loop though the `List` in `doInBackground()` and `publish()` an interim result as each on concludes? – trashgod Apr 28 '16 at 15:56
  • @trashgod the thing is I inherited this project and I didn't want to change the signature of the class since originally the person that did wrote it put all PreparedStatements in the constructor aswell as the "trips" object. I didn't want to create lets say 20 "trips" objects when 20 simulations are selected... One simulation consists of more than 2million households with more than 20million trips. I had that idea already in putting everything into the "doInBackgroung()". But unfortunately I have to adapt other classes as well then. – motaa Apr 28 '16 at 16:20
  • Sorry if I'm missing something, but the actual generic parameter `Object` is unused; the impact seems small. See also this [approach](http://stackoverflow.com/a/11372932/230513) for non-sequential tasks. – trashgod Apr 28 '16 at 16:32
  • @trashgod On the other hand I am now thinking about putting that database stuff into the `doInBackground()` method and set up 2 constructors... one for a String variable and one for a List and let the `doInBackGround()`handle the rest. That could work out. Where would I put the `publish()`method? At the end of the iteration block? – motaa Apr 28 '16 at 16:40
  • @trashgod it works. I put all the heavy DB code into the `doInBackground()` method and added an additional constructor that takes a StringArray. I will put it into the post as EDIT. I didn't even have to call `publish()` – motaa Apr 28 '16 at 18:35
  • Glad you got it sorted; I would urge you to [answer your own question](http://meta.stackoverflow.com/q/17463/163188). – trashgod Apr 29 '16 at 02:00
  • the interesting thing that currently happens is when the SwingWorker's `done()`method gets called, parts of the GUI freeze (like CPUusage bars and their Clocks). They work fine during execution of the `doInBackground()` task but freeze when the SwingWorker is done. All buttons still work except the ones that are in a JTable. Also interesting is the fact that I can still launch analysis on other simulations after a previous analysis has finished and the progress bar also works fine every time. – motaa Apr 29 '16 at 11:49

1 Answers1

1

I had to switch the code around a bit. Earlier I mentioned that I didnt want to change the signature of the class... actually I meant the signature of the constructor since this class gets instantiated by other classes.

The whole DB operations that were executed in the former constructor (I inherited the project) have been put into the doInBackground() method (where they actually should belong) and the former constructor has been overloaded as described here: Best way to handle multiple constructors in Java answer by Craig P. Motlin

public Analyzer(String simulation, DBConnector connection){

    this(new String[]{simulation}, connection);
    source = simulation;
}

public Analyzer(String[] simulation, DBConnector connection){

    super();
    for( String s : simulation) this.simulations.add(s);
    this.connection = connection;
}

As mentioned in the comments above, the publish() method wasn't needed as the statusbar updates correctly.

The list where I put all the keys is a LinkedList that gets stripped of a key during every loop cycle until it is empty.

So finally all other parts of the program that use this class still work properly and the problem is solved.

Community
  • 1
  • 1
motaa
  • 327
  • 2
  • 11