6. Многопоточность - kpb90/start_android GitHub Wiki
Handler.
В Android к thread может быть привязана очередь сообщений. В эту очередь мы можем складывать сообщения. Android будет за очередью следить и отправлять сообщения на обработку. Можно указать, чтобы сообщение ушло на обработку не сразу, а спустя определенное кол-во времени.
Handler - это механизм, который позволяет работать с очередью сообщений.
Handler привязан к конкретному thread и работает с его очередью.
Handler умеет помещать сообщения в очередь. При этом он ставит самого себя в качестве получателя этого сообщения. И когда приходит время, система достает сообщение из очереди и отправляет его адресату (т.е. в Handler) на обработку.
Handler дает нам две интересные и полезные возможности:
-
реализовать отложенное по времени выполнение кода
-
выполнение кода не в своем потоке
В этом уроке сделаем небольшое приложение. Оно будет эмулировать какое-либо долгое действие, например закачку файлов и в TextView выводить кол-во закачанных файлов. С помощью этого примера мы увидим, зачем может быть нужен Handler.
Основной поток приложения отвечает за экран, его нельзя грузить чем-то тяжелым, долгоиграющие задачи нужно переносить в отдельный поток.
Работа с view-компонентами доступна только из основного потока. Новые потоки - не имеют доступа к элементам экрана.
=> Проблема
Т.е. с одной стороны нельзя загружать основной поток тяжелыми задачам, с другой стороны – новые потоки не имеют доступа к экрану, и мы не сможем из них показать пользователю, что наша тяжелая задача как-то движется.
Решение: использовать Handler
Схема работы:
- создаем в основном потоке Handler
- в долгоиграющем потоке обращаемся к Handler и с его помощью помещаем в очередь сообщение для него же самого
- система берет это сообщение, видит, что адресат – Handler, и отправляет сообщение на обработку в Handler
- Handler, получив сообщение, обновит TextView
Таким образом Handler выступит в качестве «моста» между потоками.
Handler. Посылаем простое сообщение
Сообщение может содержать в себе атрибуты. what - самый простой вариант атрибутов arg1 и arg2 - int obj - Object
obtainMessage (int what, int arg1, int arg2) - метод для создания сообщения sendEmptyMessage(int what) - отправка сообщения sendMessage(Message msg) - отправка сообщения **handleMessage ** - метод отвечает за обработку сообщений, которые предназначены для этого Handler public void handleMessage(android.os.Message msg) {
switch (msg.what) {
// Работа с UI
}
}
AsyncTask
Основы
Чтобы работать с AsyncTask, надо создать класс-наследник и в нем прописать свою реализацию необходимых нам методов.Рассмотрим некоторые методы:
-
doInBackground – будет выполнен в новом потоке, здесь решаем все свои тяжелые задачи. Т.к. поток не основной - не имеет доступа к UI.
-
onPreExecute – выполняется перед doInBackground, имеет доступ к UI
-
onPostExecute – выполняется после doInBackground (не срабатывает в случае, если AsyncTask был отменен - об этом в следующих уроках), имеет доступ к UI
Официальный хелп дает 4 правила использования AsyncTask:
-
- объект AsyncTask должен быть создан в UI-потоке
-
- метод execute должен быть вызван в UI-потоке
-
- не вызывайте напрямую методы onPreExecute, doInBackground, onPostExecute и onProgressUpdate
-
- AsyncTask может быть запущен (execute) только один раз, иначе будет exception
Параметры. Промежуточные результаты
При описании класса-наследника AsyncTask мы в угловых скобках указываем три типа данных:
-
Тип входных данных. Это данные, которые пойдут на вход AsyncTask
-
Тип промежуточных данных. Данные, которые используются для вывода промежуточных результатов
-
Тип возвращаемых данных. То, что вернет AsyncTask после работы.
-
execute – этот метод мы явно вызываем, чтобы начать выполнение задачи. В него мы передаем набор данных определенного типа. Этот тип указан первым в угловых скобках при описании AsyncTask (в нашем примере это String).
-
publishProgress – явно вызываем в методах doInBackground, onPreExecute или onPostExecute. На вход передаем промежуточные данные определенного типа. Этот тип указан вторым в угловых скобках при описании AsyncTask (в нашем примере это Integer).
-
onProgressUpdate – метод получает на вход промежуточные результаты. Сами не вызываем, вместо этого используем метод publishProgress. То, что передаем в publishProgress, попадает в onProgressUpdate.
Итоговый результат. Метод get
Используем третий параметр AsyncTask. Это тип (класс) объекта, который должен нам вернуться из AsyncTask. Получить этот объект мы можем двумя способами:
-
Он передается на вход метода onPostExecute, который срабатывает по окончании задачи
-
Метод get возвращает нам этот объект (ждет пока не выполнится задача. Так же есть реализация get с timeout)
Cancel – отменяем задачу в процессе выполнения
Для отмены задачи рекомендуется в doInBackground периодически вызывать метод isCancelled. Как только мы выполним метод cancel для AsyncTask, isCancelled будет возвращать true. А это значит, что мы должны завершить метод doInBackground.
Т.е. метод cancel – это мы ставим метку, что задачу надо отменить. Метод isCancelled – мы же сами эту метку читаем и предпринимаем действия, для завершения работы задачи.
Метод cancel возвращает boolean. Мы получим false, если задача уже завершена или отменена.
Status – статусы задачи
-
PENDING – задача еще не запущена
-
RUNNING – задача в работе
-
FINISHED – метод onPostExecute отработал, т.е. задача успешно завершена