Java — Как использовать JProgressBar с SwingWorker

Я создаю приложение Java с загрузчиком. Моя проблема в том, что индикатор выполнения не работает. Я хочу, чтобы мой индикатор выполнения показывал ход загрузки, но не удалось. Вот часть моего кода. Индикатор прогресса просто застрял на 0%...

Скачать.класс

public void startDownload()
{
    ExecutorService executor = Executors.newSingleThreadExecutor();
    FutureTask<Void> verDownloader = new FutureTask<Void>(vd);
    FutureTask<Void> launcher = new FutureTask<Void>(dd);
    executor.execute(verDownloader);
    executor.execute(launcher);
    executor.shutdown();
} 

ВерсияDownloader.class

public class VersionDownloader implements Callable<Void>, PropertyChangeListener
{
    @Override
    public Void call() throws Exception
    {
                    done = false;
                    final SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>()
                    {
                        @Override
                        protected Void doInBackground() throws Exception
                        {
                            try
                            {
                                URL fileURL = new URL(url);
                                org.apache.commons.io.FileUtils.copyURLToFile(fileURL, path);
                            }
                            catch(Exception e)
                            {

                            }
                            return null;
                        }

                        @Override
                        public void done()
                        {
                            done = true;

                            try
                            {
                                Thread.sleep(1000);
                            }
                            catch (InterruptedException e)
                            {
                                e.printStackTrace();
                            }
                        }

                    };
                    worker.execute();
                    worker.addPropertyChangeListener(this);
                    worker.get();
                }
            }
        }
        catch(Exception e)
        {

        }
        return null;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt)
    {
        if(!done)
        {
            int progress_a = progress;
            //launcher.frame.progress is a JProgressBar
            launcher.frame.progress.setValue(progress_a);
        }
    }


}

Это какой-то неправильный код?


person Jeremy    schedule 14.10.2013    source источник


Ответы (2)


Подобные вещи менее тривиальны, чем кажутся. copyURLToFile() будет блокироваться до тех пор, пока копирование не будет завершено, так что вы получите только два события — 0% и 100%.

Если вы хотите показывать ход загрузки во время загрузки, необходимо выполнить одно условие: вы должны знать длину файла до начала загрузки (чтобы вы могли вычислять проценты). Вы могли бы получить это - может быть - путем отправки HTTP-запроса HEAD перед запуском копии, но наличие поля Content-Length в ответе зависит от сервера - для фрагментированного кодирования вы не получите эту информацию (хотя вы могли бы быть в состоянии чтобы заставить некоторые серверы сообщать вам об этом, отправляя запрос HTTP 1.0). В противном случае вы можете обмануть и выбрать произвольное количество байтов.

Если у вас есть длина или приближение, вы можете либо

  • Запустите таймер и периодически проверяйте количество загруженных байтов и сравнивайте его с размером, ИЛИ
  • Откройте URL-адрес как InputStream и выполните свой собственный цикл, чтобы скопировать байты, и на каждой итерации цикла обновите индикатор выполнения.

В любом случае убедитесь, что вы используете EventQueue.invokeLater() для обновления свойства value индикатора выполнения, иначе у вас могут возникнуть проблемы с взаимоблокировкой - небезопасно изменять компоненты Swing из любого потока, кроме потока событий.

person Tim Boudreau    schedule 14.10.2013
comment
Длина файла = размер файла? Мой загрузчик проанализирует файл XML, получит содержимое URL в файле XML и загрузит его с помощью Common-IO. - person Jeremy; 15.10.2013
comment
Да, длина файла = размер файла. Протокол HTTP допускает два способа отправки файла — старомодная загрузка HTTP 1.0, где заголовок Content-Length говорит вам, сколько байтов вы загрузите, прежде чем загружать их. HTTP 1.1 предлагает кодирование по частям, при котором сервер продолжает передавать небольшие порции байтов, каждой из которых предшествует количество байтов в этой порции. В этом случае вы не знаете, как долго загружается файл. Таким образом, для фрагментированного кодирования вы не знаете, сколько байтов вы собираетесь получить. Если вы знаете средний размер, вы можете догадаться о нем... - person Tim Boudreau; 18.10.2013
comment
Но несмотря ни на что, если вы хотите показать фактический прогресс — какой процент выполнения — вам нужен какой-то способ прослушать загрузку во время ее выполнения и обновить ее. Вы всегда можете сделать неопределенный режим на своем индикаторе выполнения, и в этом случае точное знание того, сколько байтов осталось для загрузки, не требуется. - person Tim Boudreau; 18.10.2013
comment
Трудно использовать InputStream для моего файла, потому что мне нужно делать много mkdir и что-то в этом роде. Вот почему я использую Common-IO. Можете ли вы дать мне пример кода, пожалуйста? В моем файле XML также есть <Size> для каждого файла - person Jeremy; 21.10.2013

Прочтите раздел руководства по Swing, посвященный Как использовать индикаторы выполнения. для рабочего примера, который использует SwingWorker.

Начните с того, что работает, и внесите изменения в соответствии с вашими конкретными требованиями. Если у вас все еще есть проблемы, опубликуйте SSCCE, демонстрирующий проблему.

person camickr    schedule 14.10.2013