29 October 2010

Заставляем ProgressBar крутиться пока идет http-запрос

Development for Android
Все началось с того, что мне вдруг очень захотелось сделать что-нибудь под андроид. И все это несмотря на то, что java — не мой родной язык.
В процессе создания своего приложения я столкнулся с несколькими трудностями, о решении которых и хочу поведать. Думаю, они будут полезны, таким же как я, новичкам, и буду благодарен за советы и более красивые примеры от гуру.
Но главное подтверждение работоспособности примеров — это то что приложение работает, можете проверить.

Вот несколько проблем, с которыми я столкнулся:
  • UI ждет пока придет ответ от сервера, как победить? (в этой статье)
  • Отправка и получение данных — в каком формате? (в следующей, если кому интересно)
  • Как работать с камерой? (тоже в следующей, если кому интересно)

Рассмотрим пока первую проблему.

UI ждет пока придет ответ от сервера, как победить?


Взаимодействие с сервером — ключевой момент этого приложения. Когда приложение отправляет запрос на сервер, ему приходится ждать ответа. Во время этого ожидания пользовательский интерфейс останавливается и создается впечатление, что программа подвисла. Нестрашно, если ответ получен в течении секунды, но в реальности, ждать ответа от сервера иногда приходится около 10 секунд. Чтобы сообщить пользователю, что приложение не зависло, необходимо показать ему ProgressBar. Я остановился на крутящемся колесике, как в AJAX. Вот как это выглядит:


Опишу примерно как это работает. У меня есть некий класс HttpClient, он отвечает за взаимодействие с сервером. Он же запускает и останавливает ProgressBar. Работает этот класс асинхронно. То есть приложение, запустив его не ждет пока он отработает, а может продолжать свою работу. Достигается это следующей конструкцией:
// объявляем класс
public class HttpClient extends AsyncTask<Void, Integer, Long>{
  ...
  // объявляем диалог
  public ProgressDialog dialog;
  // контекст родительского класса
  Context ctx;
  ...
  // запускаем ProgressBar в момент запуска потока
  protected void onPreExecute() {
    dialog = new ProgressDialog(ctx);
    dialog.setMessage("Поиск...");
    dialog.setIndeterminate(true);
    dialog.setCancelable(true);
    dialog.show();
  }

  // сама работа потока, SendHttpPost() - наш долгоработающий метод
  protected Long doInBackground(Void... params) {
    try {
        response = SendHttpPost();
    } catch (Exception e) {
        e.printStackTrace();
        response = null;
    }
     return null;
  }

  // как только получили ответ от сервера, выключаем ProgressBar
  protected void onPostExecute(Long unused) {
        dialog.dismiss();
        ... 
        // тут можно сообщить родительскому классу, что мы закончили
        // я делаю это немножко криво:
        ((Runnable)ctx).run();
        ....
        super.onPostExecute(unused);
  }

  ....
}


Родительский класс, который вызывает HttpClient выглядит примерно так:
public class SearchableActivity extends ListActivity implements Runnable {
  private HttpClient req;
  ...
  // этот медот вызывается, когда необходимо получить данные от сервера
  private void showResults(String query) {
    ...
    req = new HttpClient();
    req.execute((Void)null);
  }
  // этот метод вызывается из HttpClient, когда ответ от сервера получен и можно что-то с ним делать
  public void run() {
    ...
    // делаем с req то что нам нужно, если надо перерисовываем Activity
    ...
  }
}


То что я пошел по пути Runnable — мне кажется очень спорным, но на тот момент не было других мыслей.

А вот асинхронно загружать и показывать картинки я научился по этой статье: habrahabr.ru/blogs/android/78747 пользуюсь моментом сказать спасибо rude!
Tags:androidprogressbarhttpdeveloping
Hubs: Development for Android
+34
29.5k 127
Comments 22
Top of the last 24 hours