SwingWorker stoppen

Carcharoth

Bekanntes Mitglied
Guten Tag

Ich habe einen SwingWorker den ich mit einem Button auf der GUI stoppen möchte.
In der Methode doInBackground, habe ich eine Berechnungsschlaufe und darin habe ich folgende Bedingung eingebaut.

Java:
protected Void doInBackground() throws Exception {
    while (savings.getEinsparungen().size()!=0) {
        if (isCancelled()) {
            return null;
        }
        ArrayList<Weg> toursKopie = new ArrayList<Weg>(savings.iterate());
        publish(toursKopie);
    }
    return null;
}

Problem 1: wenn der User auf den Button klickt, weiss ich nicht, ob der SwingWorker bereits existiert / läuft. Ich habe es mit folgendem Workaround gelöst, aber scheint mir nicht sehr sauber. Gibt es eine bessere Lösung ?

Java:
try {
    workerVRP.cancel(true);
} catch (Exception e) {}

Problem 2: wenn ich den SwingWorker wie oben beschrieben stoppe, dann läuft er noch einen kurzen Moment (ich nehme an, er muss erstmal auf die Bedingung isCancelled treffen. Nach dem Stoppen des SwingWorkers will ich aber die grafische Darstellung auf meiner GUI bereinigen. Wenn ich das gerade im Anschluss zum Stopbefehl mache, hat der SwingWorker scheinbar nochmal Zeit die grafische Darstellung nach dem bereinigen zu zeichnen und sie ist nicht mehr bereinigt.
Wie kann ich abfragen, ob der SwingWorker nun effektiv gestoppt ist?

Danke für eure Tipps.
 
Problem 1: wenn der User auf den Button klickt, weiss ich nicht, ob der SwingWorker bereits existiert / läuft. Ich habe es mit folgendem Workaround gelöst, aber scheint mir nicht sehr sauber. Gibt es eine bessere Lösung ?
Das kann man ja alles prüfen. Du hast ihn ja in der Variable. Also kannst du prüfen:
  • ist die Variable null?
  • Du kannst getState() abprüfen sowie isCanceled().

Dann solltest Du den Button auch nur dann anbieten (aktivieren), wenn auch wirklich ein SwingWorker läuft. Du solltest also immer wissen, was der aktuelle Zustand ist und entsprechend die UI aktualisieren.

ich nehme an, er muss erstmal auf die Bedingung isCancelled treffen.
Ja genau, das ist richtig.

Wie kann ich abfragen, ob der SwingWorker nun effektiv gestoppt ist?
getState() gibt dir den State des BackgroundWorkers zurück (sowie auch isCanceled() )
Der State geht von PENDING auf STARTED hin zu DONE
 
Ich habe nun wie folgt versucht eine kleine Methode zu schreiben, um den Swingworker zu stoppen und zu warten bis er effektiv stoppt.
Der Worker stoppt aber ich habe nicht das Gefühl, dass dieser Code wirklich darauf wartet, dass der Worker fertig ist. Lässt sich auch nur schwer sagen, da das ganze schnell geht.
Was denkt ihr, theoretisch betrachtet ?

Java:
if (workerVRP.getState()==SwingWorker.StateValue.STARTED) {
    workerVRP.cancel(true);
    while (workerVRP.getState()!=SwingWorker.StateValue.DONE) {}
}
 
Also das ist so ganz schlecht:
a) Das läuft ja im UI Thread - damit hast Du den blockiert, bis der SwingWorker gestoppt ist.
b) Die while Schleife läuft mit 100% Last - das ist also auch extrem schlecht. Bei so aktivem Warten (das man eigentlich nie machen sollte, wenn es sich vermeiden lässt) muss immer ein sleep Aufruf mit rein, damit man eben nicht unnötig Last erzeugt.

Du hat eine Event basierte Lösung. Wieso kann nicht der SwingWorker ein Event auslösen, wenn er fertig ist? So Du da etwas machen musst. Dann kannst Du reagieren und machen, was auch immer du nach dem canceln machen möchtest.
 
Ok. Ich verfolge also den Ansatz aus dem SwingWorker heraus.

1. Der User klickt also auf den Button zum Abbrechen.
2. Der Listener vom Button setzt den Worker.cancel auf true.

Java:
btnStopp.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent arg0) {
        if (workerVRP.getState()==SwingWorker.StateValue.STARTED) {
            workerVRP.cancel(true);
        }
    }
});

3. Nach kurzer Zeit, wird die Bedingung auf isCancelled in der Methode doInBackground vom Worker erreicht und es wird abgebrochen.
4. Ich gehe davon aus, wenn ich ein event feuern will, dann hier, vor dem eigentlichen Abbrechen des Workers.

Java:
protected Void doInBackground() throws Exception {
    while (savings.getEinsparungen().size()!=0) {
        if (isCancelled()) {
            // fire event ?
            return null;
        }
        ArrayList<Weg> toursKopie = new ArrayList<Weg>(savings.iterate());
        publish(toursKopie);
    }
    return null;
}

Nur, wie mache ich das konkret ?
 

Neue Themen


Zurück
Oben