I have somewhat of a strange problem. I have a doAction()
Swingworker with a for
loop to remove rows from a JTable
and a data base. If the for
loop is large the done()
method will fire off before the loop is completed, effectively stopping execution midway.
My code:
public void doAction() throws Exception {
int selectedRows[];
int modelRows[];
java.util.ArrayList<customRecord> condemned;
customTableModel dataSource;
boolean databaseDelete = false;
Object uniqueID;
int rowCount = 0;
dataSource = (customTableModel)table.getModel();
selectedRows = table.getSelectedRows();
condemned = new java.util.ArrayList<customRecord>();
modelRows = new int[selectedRows.length];
for(int i=0;i<selectedRows.length;i++)
modelRows[i] = table.convertRowIndexToModel(selectedRows[i]);
selectedRows = null;
for(int i= 0; i < modelRows.length; i++){
uniqueID = dataSource.getUniqueID(modelRows[i]);
System.out.println("Debug: spot 1, rowCount = " + rowCount + ", i = " + i + ", length = " + modelRows.length);
if(uniqueID == null)
dataSource.removeRow(modelRows[i]);
else if(adminPrivileges){
condemned.add(//Record being looked at);
databaseDelete = true;
System.out.println("Debug: spot 2, rowCount = " + rowCount + ", i = " + i);
dataSource.removeRow(modelRows[i]);
if(condemned.size() >= 100){
database.clearData(condemned);
condemned.clear();
}
System.out.println("Debug: spot 3, rowCount = " + rowCount + ", i = " + i);
}
System.out.println("Debug: spot 4, rowCount = " + rowCount + ", i = " + i + ", uniqueID = " + uniqueID.toString() + "\n");
if(++rowCount >= 1000){
System.out.println("rowCount = " + rowCount + ", in break");
break;
}
}
if(databaseDelete){
if(condemned.size() > 0)
database.clearData(condemned);
loadData(table,database,filterParams);
}
}
public void done() {
System.out.println("Debug: in done()");
table.setVisible(true);
//Display warning message if the number of rows reached the limit
if(rowCount >= 1000){
// Display Limit Reached Warning;
}
}
My output here looks like:
Debug: spot 1, rowCount = 0, i = 0, length 1006
Debug: spot 2, rowCount = 0, i = 0
Debug: spot 3, rowCount = 0, i = 0
Debug: spot 4, rowCount = 0, i = 0, uniqueID = 2608
.
.
.
Debug: spot 1, rowCount = 505, i = 505, length = 1006
Debug: spot 2, rowCount = 505, i = 505
Debug: spot 3, rowCount = 505, i = 505
Debug: spot 4, rowCount = 505, i = 505, uniqueID = 3073
Debug: spot 1, rowCount = 506, i = 506, length = 1006
Debug: in done()
If the big for
loop is set to go from large to small like for(i = modelRows.length-1; i >= 0; i--)
it will get a little further:
Debug: spot 1, rowCount = 0, i = 1005, length 1006
Debug: spot 2, rowCount = 0, i = 1005
Debug: spot 3, rowCount = 0, i = 1005
Debug: spot 4, rowCount = 0, i = 1005, uniqueID = 3073
.
.
.
Debug: spot 1, rowCount = 899, i = 106, length = 1006
Debug: spot 2, rowCount = 899, i = 106
Debug: spot 3, rowCount = 899, i = 106
Debug: spot 4, rowCount = 899, i = 106, uniqueID = 2174
Debug: in done()
How can I make/allow this doAction()
method complete properly? Is there a maximum time a Swingworker will execute before the done()
method is called?
EDIT
I believe I have confused myself(and probably everyone else) in saying that doAction()
is a SwingWorker
. doAction()
is a method that is called from doInBackground()
in a class that extends SwingWorker
.
Code:
protected interface LengthyAction{
public customActions getAction();
public java.awt.Component getComponent();
public void doAction() throws Exception;
public void done();
}
private class DataSwingWorker extends javax.swing.SwingWorker{
private LengthyAction action;
public DataSwingWorker(LengthyAction targetAction){
action = targetAction;
setCursor(action.getComponent(),java.awt.Cursor.WAIT_CURSOR);
if(listener != null)
listener.actionPerformed(new java.awt.event.ActionEvent(**stuff**));
}
.
.
.
@Override
protected Object doInBackground() throws Exception {
action.doAction();
return null;
}
@Override
protected void done() {
if(listener != null)
listener.actionPerformed(new java.awt.event.ActionEvent(**stuff**));
action.done();
}
}
I found the answer to my problem, and it really had nothing to do with my initial thoughts. Taking out the:
if(condemned.size() >= 100){
database.clearData(condemned);
condemned.clear();
}
In the big doAction()
for loop makes everything work. It seems that this was causing the uniqueID's to skip forward 100 places, and I was hitting the end of the array before the end of the loop, giving a NullPointerException
.
Thanks for all the help, it did end up putting me on the correct path.
I'll try to answer the questions that so far seem answerable based on the data you've posted:
I have a doAction() Swingworker with a for loop to remove rows from a JTable and a data base ...... No, it is a doAction() method on an object that is called from a doInBackground() method.
This is not good. If you are calling doAction()
from within your SwingWorker's doInBackground()
method that means that your code is flagrantly violating Swing threading rules by making Swing calls, especially calls that mutate the state of Swing components, from within a background thread. This may in fact be the cause or at least a major contributor to your intermittent problems with the running of this background thread.
Is there a maximum time a Swingworker will execute before the done() method is called?
No. It is called when the doInBackground()
method has completed its actions and no exceptions have been found. A key issue is: are you checking for exceptions thrown during the SwingWorker's run? This would be tested by calling get()
on your SwingWorker within a try/catch block and after it has completed its actions.
How can I make/allow this doAction() method complete properly?
Unfortunately it's hard to tell based on your current code since we can't compile or run it. If still stuck, create and post your minimal example program or SSCCE.
My main recommendations: