ProgressBar

ProgressBar используется для отображения состояния выполняемой работы, например какого-либо анализа, загрузки файла и так далее.

Чтобы добавить ProgressBar на активность, достаточно определить его в коде разметки.

<ProgressBar
    android:id="@+id/progress"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />

По умолчанию, ProgressBar представляет собой вращающееся колесо, однако имеется возможность также в виде горизонтальной полосы. Для этого достаточно добавить атрибут style и выбрать горизонтальный стиль.

<ProgressBar
    android:id="@+id/progress"
    android:layout_width="150dp"
    android:layout_height="150dp"
    style="@style/Widget.AppCompat.ProgressBar.Horizontal"
    />

ProgressBar поддерживает два режима работы: детерминированный и неопределенный.

Неопределенный режим используется, когда вы не знаете, сколько времени займёт выполнение работы. По умолчанию ProgressBar использует неопределенный режим и показывает циклическую анимацию без показа достигнутого значения прогресса.

Детерминированный режим используется, когда нужно показать прогресс выполнения работы. Например, процент скачивания файла. Задать прогресс можно либо через XML, либо программно.

  1. Через XML
    В коде разметки нужно добавить атрибут android:progress и передать в него уровень достигнутого прогресса.

    <ProgressBar
        android:id="@+id/progress"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:progress="50"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        />

    По умолчанию максимальный прогресс равен 100, однако его можно изменить с помощью атрибута android:max.

    <ProgressBar
        android:id="@+id/progress"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:max="150"
        android:progress="50"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        />
  2. Программно
    В коде активности нужно определить экземпляр ProgressBar и затем указать прогресс с помощью метода setProgress(), в аргументы которого передаётся значение прогресса.

    ProgressBar progressBar = findViewById(R.id.progress);
    progressBar.setProgress(50);

    Кроме того, можно не задавать конкретный прогресс, а увеличивать текущий на определенную величину. Для этого можно воспользоваться методом incrementProgressBy().

    progressBar.setProgress(40); // прогресс = 40
    progressBar.incrementProgressBy(50); // прогресс = 90

    Аналогично способу в XML, можно программно задать максимальное значение прогресса следующим образом.

    progressBar.setMax(150);

Если вам нужно узнать текущий прогресс, либо максимальное значение, вы можете воспользоваться методами getProgress() и getMax() соответственно.

ProgressBar progressBar = findViewById(R.id.progress);
progressBar.setProgress(40);
Toast.makeText(this, "Прогресс - "
    + progressBar.getProgress()
    + "\nМаксимальное значение - "
    + progressBar.getMax(), Toast.LENGTH_SHORT).show();

Допустим, нам нужно скачать какой-либо файл из Интернета, отображая прогресс загрузки на экране. Разместим на активности ProgressBar и Button, который будет запускать загрузку.

Поскольку загрузка может быть весьма затратной по ресурсам операцией, её лучше всего выполнять в отдельном потоке, возвращая в основной только результат выполнения. Поэтому создадим класс DownloadTask, наследующий от AsyncTask. Его задачей будет являться загрузка файла.

public class DownloadTask extends AsyncTask<String, Integer, Boolean> {
  public interface DownloadListener {
    void onDownloadComplete(File filename);

    void onProgressUpdate(int progress);

    void onDownloadFailure(final String msg);
  }

  private final DownloadListener listener;
  private String msg;
  private File saveTo;

  public DownloadTask(DownloadListener listener) {
    this.listener = listener;
  }

  @Override protected Boolean doInBackground(String... params) {
    if (params == null || params.length < 2) {
      msg = "Incomplete parameters";
      return false;
    }

    String sUrl = params[0];
    String filename = params[1];
    File rootDir = Environment.getExternalStorageDirectory();
    saveTo = new File(rootDir, filename);

    try {
      URL url = new URL(sUrl);
      URLConnection conn = url.openConnection();
      conn.connect();
      int fileLength = conn.getContentLength();
      InputStream is = new BufferedInputStream(url.openStream());
      OutputStream os = new FileOutputStream(saveTo);
      byte buffer[] = new byte[512];
      long totalDownloaded = 0;
      int count;

      while ((count = is.read(buffer)) != -1) {
        totalDownloaded += count;

        publishProgress((int) (totalDownloaded * 100 / fileLength));
        os.write(buffer, 0, count);
      }

      os.flush();
      os.close();
      is.close();
      return true;
    } catch (MalformedURLException e) {
      msg = "Invalid URL";
    } catch (IOException e) {
      msg = "No internet connection";
    }

    return false;
  }

  @Override protected void onProgressUpdate(Integer... values) {
    if (listener != null) listener.onProgressUpdate(values[0]);
  }

  @Override protected void onPostExecute(Boolean result) {
    if (!result) {
      if (listener != null) listener.onDownloadFailure(msg);
      return;
    }

    if (listener != null) listener.onDownloadComplete(saveTo);
  }
}

Также в этом классе добавлен интерфейс DownloadListener, с помощью которого в основной поток будет передаваться прогресс загрузки, а также результат операции.

У класса AsyncTask уже реализован метод onProgressUpdate(), который позволяет возвращать прогресс выполнения операции. Чтобы передать в него значения, нужно вызвать метод publishProgress() внутри doInBackground().

Определим ProgressBar и Button в коде активности и добавим для кнопки слушатель, внутри которого будет запускаться AsyncTask, выполняющий загрузку файла. Прогресс операции будет обновляться в методе интерфейса onProgressUpdate(), куда передаётся текущее значение прогресса.

progressBar = findViewById(R.id.progress);
btn_start = findViewById(R.id.btn_start);
btn_start.setOnClickListener(new View.OnClickListener() {
  @Override public void onClick(View view) {
    String url = "https://imagine.gsfc.nasa.gov/Images/news/G306_color_large.jpg";
    String filename = "G306.jpg";
    DownloadTask downloadTask = new DownloadTask(new DownloadTask.DownloadListener() {
      @Override public void onDownloadComplete(File filename) {
        Toast.makeText(getApplicationContext(), filename + " загружен", Toast.LENGTH_SHORT)
            .show();
      }

      @Override public void onProgressUpdate(int progress) {
        progressBar.setProgress(progress);
      }

      @Override public void onDownloadFailure(String msg) {
        Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
      }
    });
    downloadTask.execute(url, filename);
  }
});

Также можно выводить значение в процентах под ProgressBar, добавив текстовых полей.