为什么 doAction() 提前到 done() ?

Why is doAction() getting to done() early?

我遇到了一个奇怪的问题。我有一个带有 for 循环的 doAction() Swingworker,用于从 JTable 和数据库中删除行。如果 for 循环很大,done() 方法将在循环完成之前触发,有效地中途停止执行。

我的代码:

 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;
    }
}

我的输出如下:

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()

如果大 for 循环设置为像 for(i = modelRows.length-1; i >= 0; i--) 从大到小,它会更进一步:

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()

我怎样才能make/allow这个doAction()方法正确完成?在调用 done() 方法之前,Swingworker 是否有最长时间执行?

编辑

我相信我自己(可能还有其他人)在说 doAction()SwingWorker 时感到困惑。 doAction() 是从扩展 SwingWorker.

的 class 中的 doInBackground() 调用的方法

代码:

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();
    }

}

我找到了我的问题的答案,这真的与我最初的想法无关。取出:

if(condemned.size() >= 100){
    database.clearData(condemned);
    condemned.clear();
}

在大 doAction() for 循环中,一切正常。这似乎导致 uniqueID 向前跳过 100 个位置,我在循环结束前到达数组的末尾,给出 NullPointerException.

感谢所有帮助,它最终让我走上了正确的道路。

我将尝试根据您 post 编辑的数据回答到目前为止似乎可以回答的问题:

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.

这样不好。如果您从 SwingWorker 的 doInBackground() 方法中调用 doAction(),这意味着您的代码通过在后台线程中进行 Swing 调用,尤其是改变 Swing 组件状态的调用,公然违反了 Swing 线程规则.这实际上可能是造成您与此后台线程 运行 连接间歇性问题的原因或至少是主要原因。

Is there a maximum time a Swingworker will execute before the done() method is called?

没有。当 doInBackground() 方法完成其操作并且未发现异常时调用它。一个关键问题是:您是否正在检查 SwingWorker 运行 期间抛出的异常?这将通过在 try/catch 块内并在它完成其操作后对您的 SwingWorker 调用 get() 来测试。

How can I make/allow this doAction() method complete properly?

遗憾的是,根据您当前的代码很难判断,因为我们无法编译或 运行 它。如果仍然卡住,请创建并 post 您的 minimal example program or SSCCE.

我的主要建议:

  1. 首先,重写所有这些代码,使其严格遵循 Swing 线程规则。这最有可能解决您的问题。了解 SwingWorkers 自动允许 PropertyChangeListener 支持,因此这可能是在后台线程和 Swing 事件线程之间进行通信的好方法。
  2. 接下来一定要重构代码,使您的 类 成为可独立测试的小单元,然后通过尝试让它们以您能想到的任何方式失败来最大限度地测试它们中的每一个。