I am trying to improve my SwingWorker class ImageWorker. ImageWorker is intended to be used on large arrays of images. ImageWorker is periodically called to load new images while the array indices of seen images are set to null. This is why it only loads up to i < currentPosition+40 which prevents it from trying to load the whole array in one go which is too much for slower machines. Currently it needs to load all 40 images before it will run the done() method on the EDT. At points where I don't have time to start ImageWorker early this causes a single delay of a few milliseconds.
I would like to implement publish/process, but I can't seem to find an example of using these methods with arrays. Is there a known good practice for using publish/process with array return type? Or should I be trying to publish single images as imageArray[i] and then using process to incorporate those images into the appropriate array? I can't seem to find any code that uses arrays for these methods, just Strings and ints.
Credit to trashgod for helping me get started with ImageWorker in the first place. My original question has evolved enough that it probably warrants this new thread. The original thread contains an SSCCE of the code that ImageWorker is used in and can be found here: Full Code.
private class ImageWorker extends SwingWorker<Image[], Image>
{
private int currentPosition;
private int arraySize;
private String trickName;
private Image[] imageArray;
public ImageWorker(int arraySize, int currentPosition, String trick)
{
super();
this.currentPosition = currentPosition;
this.arraySize = arraySize;
this.trickName = trick;
}
@Override
public Image[] doInBackground()
{
imageArray = new Image[arraySize];
for(int i = currentPosition; i < currentPosition+40 && i < arraySize; i++)
{
try
{
imageArray[i] = ImageIO.read(new File("images/" + trickName + (i+1) + ".jpg"));
}
catch (IOException e)
{
System.out.println(trickName);
System.out.println(e.getMessage());
System.exit(0);
}
}
return imageArray;
}
@Override
public void done()
{
try
{
if(trickName.equals("handCuffs"))
{
handCuffs = get();
}
else if(trickName.equals("cups"))
{
cups = get();
}
}
catch(InterruptedException ignore){}
catch(java.util.concurrent.ExecutionException e)
{
String why = null;
Throwable cause = e.getCause();
if(cause != null)
{
why = cause.getMessage();
}
else
{
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
}
It seems I should be using publish on each image in the for loop and then using process to put them as elements in the array. The process part seems more difficult. I edited the above code to include a process method, but it doesn't work right yet.
private class ImageWorker extends SwingWorker<Image[], Image>
{
private int currentPosition;
private int arraySize;
private String trickName;
private Image[] imageArray;
public ImageWorker(int arraySize, int currentPosition, String trick)
{
super();
this.currentPosition = currentPosition;
this.arraySize = arraySize;
this.trickName = trick;
i = currentPosition;
}
@Override
public Image[] doInBackground()
{
imageArray = new Image[arraySize];
for(int i = currentPosition; i < currentPosition+40 && i < arraySize; i++)
{
try
{
imageArray[i] = ImageIO.read(new File("images/" + trickName + (i+1) + ".jpg"));
publish(imageArray[i], i);
}
catch (IOException e)
{
System.out.println(trickName);
System.out.println(e.getMessage());
System.exit(0);
}
}
return imageArray;
}
@Override
public void process(List<Image> chunks, int i)
{
for(Image element: chunks)
{
if(trickName.equals("handCuffs"))
{
handCuffs[i] = element;
}
else if(trickName.equals("cups"))
{
cups[i] = element;
}
}
}
@Override
public void done()
{
try
{
if(trickName.equals("handCuffs"))
{
handCuffs = get();
}
else if(trickName.equals("cups"))
{
cups = get();
}
}
catch(InterruptedException ignore){}
catch(java.util.concurrent.ExecutionException e)
{
String why = null;
Throwable cause = e.getCause();
if(cause != null)
{
why = cause.getMessage();
}
else
{
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
}
The issue with the process method is that I can't figure out how to set the correct index for the array the elements from publish will be written to. I would like publish to pass the index as well as the image, but this violates the return type set by the class. Can publish only have one type of argument?
Thanks to trashgod and MadProgrammer with all your help on this. In case anyone else wants to implement a similar SwingWorker, here's my final code including the wrapper class for encapsulating arrayImage[i] and the corresponding index int i.
private class ArrayWrapper
{
private int i;
private Image image;
public ArrayWrapper(Image image, int i)
{
this.i = i;
this.image = image;
}
public int getIndex()
{
return i;
}
public Image getImage()
{
return image;
}
}
private class ImageWorker extends SwingWorker<Image[], ArrayWrapper>
{
private int currentPosition;
private int arraySize;
private String trickName;
private Image[] imageArray;
public ImageWorker(int arraySize, int currentPosition, String trick)
{
super();
this.currentPosition = currentPosition;
this.arraySize = arraySize;
this.trickName = trick;
}
@Override
public Image[] doInBackground()
{
imageArray = new Image[arraySize];
for(int i = currentPosition; i < currentPosition+40 && i < arraySize; i++)
{
try
{
imageArray[i] = ImageIO.read(new File("images/" + trickName + (i+1) + ".jpg"));
ArrayWrapper wrapArray = new ArrayWrapper(imageArray[i], i);
publish(wrapArray);
}
catch (IOException e)
{
System.out.println(trickName);
System.out.println(e.getMessage());
System.exit(0);
}
}
return imageArray;
}
@Override
public void process(List<ArrayWrapper> chunks)
{
for(ArrayWrapper element: chunks)
{
if(trickName.equals("handCuffs"))
{
handCuffs[element.getIndex()] = element.getImage();
}
else if(trickName.equals("cups"))
{
cups[element.getIndex()] = element.getImage();
}
}
}
@Override
public void done()
{
try
{
if(trickName.equals("handCuffs"))
{
handCuffs = get();
}
else if(trickName.equals("cups"))
{
cups = get();
}
}
catch(InterruptedException ignore){}
catch(java.util.concurrent.ExecutionException e)
{
String why = null;
Throwable cause = e.getCause();
if(cause != null)
{
why = cause.getMessage();
}
else
{
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
}