Справочник по 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();
}
}
});