Как связать несколько SwingWorkers

У меня есть большая фоновая задача с некоторыми промежуточными точками, где требуется ввод данных пользователем.

Например. buttonLoad_actionPerformed --> загрузить, проверить достоверность --> если устарело, спросить пользователя, следует ли обновлять. Если да --> обновите, если нет --> остановитесь.

На данный момент я закодировал это так:

// load worker
SwingWorker<Status,Object> swLoad=new SwingWorker<> () {
    Validity doInBackGround() {
        return load(file);
    }

    void done() {
        Validity validity=get();

        switch (validity) {
            case UPTODATE:
                return;
            case OUTDATED:
                int res=JOptionPane.showConfirmDialog("File obsolete. Do you want to update it ?");
                if (res != JOptionPane.YES_OPTION) 
                    return;
                    
                // update worker
                SwingWorker<Boolean,Object> swUpdate = new SwingWorker<>() {
                    Boolean doInBackGround() {
                        return update();
                    }

                    void done() {
                        Boolean success=get();
                        if (!success) ....
                    }
                };
                
                swUpdate.execute();
        }    
    }
};

swLoad.execute();

Однако это может стать довольно нечитаемым, если требуется несколько шагов.

Каков наилучший подход для объединения условных/необязательных SwingWorkers?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Учитывая, что это немного неясный вопрос, я попробую.

Есть 2 пункта, которые выделяются для меня:

  1. Показанная функция/метод довольно длинная
  2. Происходит много вложений

Простое решение для их улучшения — разделить код на отдельные методы. Например, переместите активный код из случая «УСТАРЕЛО» в отдельный метод. Конечно, это дольше, но легче следовать.

public loadInWorker() {
    SwingWorker<Status,Object> swLoad=new SwingWorker<> () {
        Validity doInBackGround() {
            return load(file);
        }

        void done() {
            onLoad(get());
            }
        }
    };

    swLoad.execute();
}



private onLoad(Validity validity) {
    switch (validity) {
        case UPTODATE:
            return;
        case OUTDATED:
            int res=JOptionPane.showConfirmDialog("File obsolete. Do you want to update it ?");
            if (res == JOptionPane.YES_OPTION) {
                updateInWorker(); 
            }
    }
}



private updateInWorker() {
    SwingWorker<Boolean,Object> swUpdate = new SwingWorker<>() {
        Boolean doInBackGround() {
            return update();
        }

        void done() {
            Boolean success=get();
            if (!success) {
                onUpdateFailure();
            }
        }
    };

    swUpdate.execute();
}


private onUpdateFailure() {
    ....
}

Редактировать + Мнение: Добавлю, что я никогда не использовал этот рабочий API. Глядя на него, он кажется довольно запутанным. В последние дни разработки на Java я полагался на ThreadPools для задач с коротким временем выполнения и на выделенные потоки для задач с длительным временем выполнения. Вы также можете написать оболочку для вызова SwingWorker, поскольку вам не нужны внутренние типы вне его. Пример использования болотных стандартных потоков:

public loadInThread() {
    new Thread(this::loadInThread, "Load Thread").start();
}


private loadInThread() {
    switch (load(file)) {
        case UPTODATE:
            return;
        case OUTDATED:
            int res=JOptionPane.showConfirmDialog("File obsolete. Do you want to update it ?");
            if (res == JOptionPane.YES_OPTION) {
                new Thread(this::updateInThread, "Update Thread").start();
            }
    }
}



private updateInThread() {
    if (!update()) {
        // Update Failure code goes here
    }
}

Смысл использования рабочего процесса Swing заключается в том, что состояние всех компонентов Swing должно обновляться в потоке отправки событий (EDT), а не в обычном потоке. Прочитайте учебник по Swing на Concurrency для получения дополнительной информации.

camickr 22.06.2023 15:34
Ответ принят как подходящий

Я не понимаю, почему вы что-то делаете в своем методе done.

Validity doInBackGround() {
    Validity validity = load(file);
    switch (validity) {
        case UPTODATE:
            return validity;
        case OUTDATED:
            int res= confirmOnEdt();
            if (res == JOptionPane.YES_OPTION) {
                Boolean success = update();
                //check the update and respond.
            }
    }
    return validity;
}

public int confirmOnEDT() throws InterruptedException{
    int[] container = {0};
    SwingUtilities.invokeAndWait( ()->{
            container[0] = JOptionPane.showConfirmDialog("File obsolete. Do you want to update it ?");
        }
    );
    return container[0];
}

Один SwingWorker для полного набора задач. JOptionPane заблокирует ваш фоновый поток и будет ждать ввода. Кроме того, вы, вероятно, хотите, чтобы возвращаемое значение отличалось от Validity.

Разве JOptionPane.showConfirmDialog не следует называть в EDT и, следовательно, в done()?

lvr123 23.06.2023 09:35

Если вы должны вызвать его в EDT, тогда оберните звонок в SwingUtilities.invokeAndWait() Было бы полезно, если бы мы знали, чего вы хотите от результата в конечном итоге. У вас есть несколько этапов выполнения с обменом данными между EDT/GUI и вашим фоновым потоком. Способ, который вы предложили, действителен. Запустите нового Swing Worker для выполнения новой фоновой задачи. Хотя ваш пример не оправдывает этого.

matt 23.06.2023 11:39

Я отредактировал ответ, включив в него отображение диалогового окна в EDT. Вы можете видеть, что это также немного громоздко. Я думаю, что лучший дизайн — это знать свои данные. Графический интерфейс ссылается на ваши данные через модель. Ваш первый щелчок каким-то образом изменяет данные с помощью Swing Worker. Как только этот рабочий закончит работу, ваши данные перейдут в новое состояние. Затем вы ждете, пока графический интерфейс снова изменит данные. Для чего может потребоваться еще один свинг-воркер. Y может научиться избегать вложенности свинг-воркеров.

matt 23.06.2023 11:57

Я не должен звонить JOptionPane.showConfirmDialog в EDT. Я просто подумал, что лучше всего вызывать любое действие GUI в EDT. В том числе JOptionPane.

lvr123 23.06.2023 12:23

Другие вопросы по теме