3. Main Thread (UI Thread)
По умолчанию все работает в имеено в нем
UI потоконебезопасен: попытка что-либо сделать с View из другого потока выбросит
исключение.
Если занять поток больше чем на 5 секунд, появится диалог ANR (Application Not
Responding) с предложением убить приложение.
Начиная с Android 3.0 в инструментах разработчика появился strict mode, который бросает
исключение если разработчик сделал что-то не так. Полез в интернет из главного потока
или начал читать файл? Получай исключение!
6. Асинхронное поведение
Thread/Executor, т.е., все, что есть в java
AsyncTask - стандартный класс для асинхронных задач
Service/IntentService - компонент приложения, который не имеет UI и работает как фоновая
задача
Loader (API >= 11) - более современный механизм запуска асинхронных задач
Handler - компонент, ассоциированный с потоком, который позовляет работать с очередью
сообщений.
8. Handler
Handler — это ассоциированный с потоком объект, обрабатывающий сообщения. Обработка
сообщений происходит либо в объекте, который передается в конструкторе:
1 Handler handler =
2 new Handler(Looper.getMainLooper(), new Handler.Callback(){...});
Либо расширением самого Handler и реализацией его метода handleMessage(final Message msg)
1 class DemoHandler extends Handler {
2 @Override
3 public void handleMessage(final Message msg) {
4 //
5 }
6 }
Альтернативой является использование Runnable, в нем же и содержится код, выполняемый
при обработке сообщения.
9. Handler
По умолчанию Runnable отправляется в конец очереди. Однако, можно отправить с
задержкой, в указанное время и в самое начало очереди:
handler.post(Runnable r)
handler.postDelayed(Runnable r, long delay)
handler.postAtTime(Runnable r, long time)
handler.postAtFrontOfQueue(Runnable r)
То же самое можно проделать и с сообщением;
handler.sendMessage(Message msg)
handler.sendMessageDelayed(Message msg, long delay)
handler.sendMessageAtTime(Message msg, long time)
handler.sendMessageAtFrontOfQueue(msg)
10. AsyncTask
Типичный пример асинхронного поведения:
1. Сделать что-то в главном потоке, например вывести диалог начала загрузки
2. Запустить задачу в другом потоке и время от времени обновлять статус задачи (например
прогресбар)
3. После завершения задачи сообщить о результате
12. AsyncTask
1 public class DemoAsyncTask extends AsyncTask<String, Integer, Boolean> {
2 @Override
3 protected Boolean doInBackground(final String... params) {
4 Boolean result = false;
5 // Do something
6 for (int i = 0; i < 10; i++) {
7 publishProgress(i);
8 }
9 return result;
10 }
11
12 @Override
13 protected void onPostExecute(final Boolean aBoolean) {
14 // Show result
15 }
16
17 @Override
18 protected void onProgressUpdate(final Integer... values) {
19 // Update progress
20 }
21 }
13. AsyncTask
И использование:
1 DemoAsyncTask demoTask= new DemoAsyncTask();
2 demoTask.execute("Argument 1", "Argument 2");
Чем параметризуется AsycTask:
1. Тип массива входных аргументов в методе execute и doInBackground
2. Тип обновления прогресса
3. Тип результата
Если что-то из этого не предполагается, можно использовать Void.
14. AsyncTask
В зависимости от версии API AsyncTask ведет себя по-разному:
4 < API < 13 — каждый новый AsyncTask работает в новом потоке
API ≥ 13 (3.2+) - на все AsyncTask выделяется один поток, но добавили поле
AsyncTask.THREAD_POOL_EXECUTOR.
Причем, THREAD_POOL_EXECUTOR неодинаков для разных API:
API < 19 от 5 до 128 потоков, длина очереди — 10.
API ≥ 19 от N+1 до 2N+1 потоков, длина очереди — 128. N - количество ядер процессора
устройства.
16. Service
Сервис обязательно объявляется в манифесте
1 <manifest ... >
2 ...
3 <application ... >
4 <service android:name=".service.DemoService" />
5 ...
6 </application>
7 </manifest>
Также у тега <service> есть ряд атрибутов:
name - имя класса, реализующего Service
exported - могут ли другие приложения взаимодействовать с этим сервисом
isolatedProcess - будет ли сервис работать как отдельный процесс
permission - разрешение, требуемое для запуска этого сервиса
process - имя процесса, в котором сервис будет запущен.
label - имя процесса, отображаемое пользователю
17. Приоритеты Service
По умолчанию сервисы имеют приоритет background
Чтобы повысить приоритет до foreground или понизить обратно нужно воспользоваться
методами:
startForeground()
stopForeground()
Также можно узнать о том, что системе не хватает памяти и она может убить сервис:
onLowMemory()
onTrimMemory() — API >=14
18. IntentService example
1 public class DemoIntentService extends IntentService {
2 public DemoIntentService() {
3 // Service name is used for debugging
4 super("DemoIntentService");
5 }
6
7 @Override
8 protected void onHandleIntent(final Intent intent) {
9 // Do stuff
10 }
11 }
19. Loader
Появился в API 11
Привязан к методам жизненного цикла activity или fragment
Основные компоненты
LoaderManager - создает, уничтожает, запускает, пересоздает Loader
LoaderManager.LoaderCallbacks - интерфейс для связи клиента и менеджера
Loader - объект, асинхронно выполняющий задачу.
20. Работа с сетью
Чаще всего под работой с сетью подразумевают взаимодействие с REST-подобными
cервисами, т.е. HTTP + JSON/XML
Для доступа в сеть требуется разрешение android.permission.INTERNET. Также может
понадобиться разрешение android.permission.ACCESS_NETWORK_STATE для проверки
доступности сети.
Для отображения web-страниц можно использовать WebView - практически полноценный
браузер. Начиная с Android 4.4 основан на Chromium и регулярно обновляется.
22. HttpClient
Типичный use-case
Создается HttpClient (DefaultHttpClient или AndroidHttpClient)
Создается и настраивается запрос – объект класса HttpUriRequest (обычно HttpGet или
HttpPost)
Выполняется запрос HttpClient.execute и получаем в ответ HttpResponse
Разбирается HttpResponse – заголовки, строка ответа и т.д.
Получается HttpEntity и разбирается тело ответа HttpClient
23. HttpUrlConnection
Типичный use-case
Создается объект URL, вызывается openConnection() и делается приведение к
HttpURLConnection
Подготавливается запрос – устанавливается хедеры, параметры запроса, тип контента и
т.д.
По необходимости подгатавливается тело запроса (POST запрос). setDoOutput(true) и
getOutputStream()
Читается ответ сервера. Строку ответа (код, сообщение), заголовки, cookie и т.д.
Закрывается соединение и освобождаются ресурсы
25. OkHttp / Retro t
OkHttp - библиотека для работы с HTTP от SquareUp.
Retro t - библиотека для работы с REST API от SquareUp, на Android по умолчанию
использует HttpUrlConnection. Однако лучше подключать OkHttp, из-за багов в
HttpUrlConnection.
26. Бочка дегтя
1. Асинхронность через callback приводит к росту вложенности, отсюда вытекает
запутанность кода, проблемы с сопровождением и т.д. (т. н. Callback-hell)
2. Компонент, запустивший AsyncTask запросто может благополучно умереть, что вызывает
проблемы с доставкой результата
3. Регулярно приходится загружать картинки, зачастую адаптерах ListView
4. К бекэнду часто нужно строить кеш на стороне приложения
5. Часто результат выполнения сетевого запроса нужен в разных местах приложения
27. Решения
1. RxJava
2. Проверять, жив ли компонент, подпирать все это костылями / использовать EventBus
3. Picasso / Glide / ...
4. ORM, сохранение в файлы, SharedPreferences — по ситуации
5. Otto / Event bus
28. Дополнительные материалы
Более подробная презентация о многопоточности и асинхронности
Более подробная статья о сервисах
Цикл статей о Loader с примерами
Реактивные расширения RxJava
Picasso
Retro t
Еще примеры