вторник, 13 декабря 2011 г.

Потоки Андроид


Справочник по android API

Потоки

В андроиде добавлены дополнительные возможности для работы с потоками.

Класс Handler

Когда объект Handler создается, он назначается текущему потоку и его очереди сообщений. После этого он может доставлять сообщения и код (Runnable) в очередь сообщений для обработки и выполнения их в будущем. Таким образом, объект используется для одновременной обработки сообщений и выполнения некоторого кода или для выполнения кода в другом потоке. Ниже приведены некоторые методы класса:
  • dispatchMessage(Message msg) - обработчик системных сообщений
  • dump(Printer pw, String prefix) - дамп
  • handleMessage(Message msg) - обработчик входящих сообщений, должен переопределятся потомками
  • hasMessages(int what, Object object) - проверяет есть ли не обработанное сообщение с кодом 'what' и объектом сообщения 'object'
  • hasMessages(int what) - проверяет есть ли не обработанное сообщение с кодом 'what'
  • Message obtainMessage() - новое сообщение из глобального пула сообщений, есть вариации метода
  • boolean post(Runnable r) - послать r в очередь сообщений (т.е. выполнить код в потоке, в котором объект Handle был создан)
  • void removeCallbacks(Runnable r) - удалить все посланные r из очереди сообщений
  • void removeMessages(int what) - удалить сообщение с кодом 'what' из очереди
  • boolean sendMessage(Message msg) - поместить сообщение в конец очереди сообщений

метод runOnUiThread

Метод runOnUiThread класса Activity позволяет выполнить указанный код в UI потоке. Если текущий поток - UI поток, то он выполняется сразу, иначе помещается в очередь событий UI потока.
Обычно используется, когда нужно изменить элементы управления после выполнения какой-то задачи в другом потоке.

// снипет подгрузки изображения из интернета и установки его в виджет ImageView
(new Thread(new Runnable() {

 @Override
 public void run() {
   try {
   final Bitmap bm = ImageTool.loadBitmap(urlImg);
   CompanyView.this.runOnUiThread(new Runnable() {
                                    
      @Override
      public void run() {
         ico.setImageBitmap(bm);                                        
         }
      });
                                
   } catch (Exception e) {
        e.printStackTrace();
        }
   }
   })).start();

Класс AsyncTask

Класс AsyncTask облегчает выполнения задачи в отдельном потоке, с последующем отображением результата в потоке пользовательского интерфейса (UI).
Шаблон класса использует три типа
  • Params - тип параметров посылаемых перед запуском задачи;
  • Progress - тип, используемый для отображения прогресса операции;
  • Result - тип результата задачи;
Ниже приведены некоторые методы класса:
  • onPreExecute() - вызывается в потоке UI сразу после запуска задачи, на данном этапе обычно настраивают задачу, например, показывая индикатор прогресса в UI;
  • doInBackground(Params...) - запускается в отдельном потоке после завершения onPreExecute(). На этом этапе вычисляется результат, который передается методу onPostExecute;
  • Также на этом этапе могут использоваться вызовы publishProgress() для отображения текущего прогресса выполнения задачи;
  • onProgressUpdate(Progress...) - вызывается в потоке UI сразу после вызова publishProgress(). Метод используется для отображения прогресса в пользовательском интерфейсе;
  • onPostExecute(Result) - вызывается в потоке UI после завершения задачи;
  • execute(Params... params) - выполняет задачу с указанными параметрами;
  • isCancelled() - true, если задача была прервана;
  • cancel(boolean mayInterruptIfRunning) - попытка прервать задачу;

// пример из документации - загрузка файлов
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }
 
 ...
 
 new DownloadFilesTask().execute(url1, url2, url3);
Задача должна запускаться из главного потока пользовательского интерфейса, иначе система выдаст ошибкуjava.lang.ExceptionInInitializerError.
Задачу можно запускать только один раз.

// При повторном запуске задачи система выдаст ошибку
//  Cannot execute task: the task has already been executed 
//  (a task can be executed only once)
at = new DownloadFilesTask();
at.execute(url1, url2, url3);
...
at.execute(url1, url2, url3);

// правильно
at = new DownloadFilesTask();
at.execute(url1, url2, url3);
...
at = new DownloadFilesTask();
at.execute(url1, url2, url3);

метод View.post

Если пытаться получить высоту TextView после изменения содержимого, результат скорей всего будет неверным.
В этом случае высота запрашивается через метод post класса View. Указанная задача будет добавлена в очередь сообщений и выполнена в потоке UI.

TextView tvDescription;
...
tvDescription.setText("example for darkraha.com"));
tvDescription.post(new Runnable() {

       @Override
       public void run() {
           if(tvDescription.getMeasuredHeight() > getCollapsedHeight()){            
              evDescription.setCollapse();
           }
         }
});

Комментариев нет:

Отправить комментарий