Android java background process

Introduction to background processing in Android — Tutorial

This tutorial introduces the concept of asynchronous processing in Android applications.

1. Background processing in Android

1.1. Why using concurrency?

By default, application code runs in the main thread. Every statement is therefore executed in sequence. If you perform a long lasting operation, the application blocks until the corresponding operation has finished.

To provide a good user experience all potentially slow running operations in an Android application should run asynchronously. This can be archived via concurrency constructs of the Java language or of the Android framework. Potentially slow operations are for example network, file and database access and complex calculations.

Android enforces a worst case reaction time of applications. If an activity does not react within 5 seconds to user input, the Android system displays an Application not responding (ANR) dialog. From this dialog the user can choose to stop the application.

1.2. Main thread

Android modifies the user interface and handles input events from one single thread, called the main thread. Android collects all events in this thread in a queue and processes this queue with an instance of the Looper class.

1.3. Threading in Android

Android supports the usage of the Thread class to perform asynchronous processing. Android also supplies the java.util.concurrent package to perform something in the background. For example, by using the ThreadPools and Executor classes.

If you need to update the user interface from a new Thread , you need to synchronize with the main thread. Because of this restrictions, Android developer typically use Android specific code constructs.

Standard Android provides the android.os.Handler class or the AsyncTasks classes. More sophisticated approaches are based on open source solutions which are using callbacks.

For example, the RxJava open source framework allow to specify an observer of an observable stream of data. Once the events happen the observer is called by the framework. You can configure in which thread the observer and observable run.

2. Handler

2.1. Purpose of the Handler class

A Handler object registers itself with the thread in which it is created. It provides a channel to send data to this thread, for example the main thread. The data which can be posted via the Handler class can be an instance of the Message or the Runnable class. A Handler is particular useful if you have want to post multiple times data to the main thread.

2.2. Creating and reusing instances of Handlers

To implement a handler subclass it and override the handleMessage() method to process messages. You can post messages to it via the sendMessage(Message) or via the sendEmptyMessage() method. Use the post() method to send a Runnable to it.

To avoid object creation, you can also reuse the existing Handler object of your activity.

The View class allows you to post objects of type Runnable via the post() method.

2.3. Example

The following code demonstrates the usage of an handler from a view. Assume your activity uses the following layout.

With the following code the ProgressBar get updated once the users presses the Button .

3. AsyncTask

The AsyncTask class allows to run instructions in the background and to synchronize again with the main thread. It also reporting progress of the running tasks. AsyncTasks should be used for short background operations which need to update the user interface.

To use AsyncTask you must subclass it. The parameters are the following AsyncTask .

An AsyncTask is started via the execute() method. This execute() method calls the doInBackground() and the onPostExecute() method.

TypeOfVarArgParams is passed into the doInBackground() method as input. ProgressValue is used for progress information and ResultValue must be returned from doInBackground() method. This parameter is passed to onPostExecute() as a parameter.

Читайте также:  Яндекс впн отключить андроид

The doInBackground() method contains the coding instruction which should be performed in a background thread. This method runs automatically in a separate Thread .

The onPostExecute() method synchronizes itself again with the user interface thread and allows it to be updated. This method is called by the framework once the doInBackground() method finishes.

3.1. Parallel execution of several AsyncTasks

By default, AsyncTask tasks are executed sequence (for Android versions higher than Android 3.0). To run AsyncTasks in sequence use the executeOnExecutor() method specifying AsyncTask.THREAD_POOL_EXECUTOR as first parameter.

3.2. Example: AsyncTask

The following code demonstrates how to use the AsyncTask to download something from the Internet. The code requires the android.permission.INTERNET permission in your Android manifest.

4. Background processing and lifecycle handling

4.1. Retaining state during configuration changes

One challenge in using threads is to consider the lifecycle of the application. The Android system may kill your activity or trigger a configuration change which will also restart your activity.

You also need to handle open dialogs, as dialogs are always connected to the activity which created them. In case the activity gets restarted and you access an existing dialog you receive a View not attached to window manager exception.

4.2. Using the application object to store objects

You can implement an Application class for your Android application.

To use your application class assign the classname to the android:name attribute of your application.

The application class is automatically created by the Android runtime and is available unless the whole application process is terminated.

This class can be used to access objects which should be cross activities or available for the whole application lifecycle. In the onCreate() method you can create objects and make them available via public fields or getter methods.

The onTerminate() method in the application class is only used for testing. If Android terminates the process in which your application is running all allocated resources are automatically released.

You can access the Application via the getApplication() method in your activity.

5. Headless Fragments and background processing

Fragments which do return null in the onCreateView methods are called headless fragments, as the provide no views. Headless fragments can retain there fields between configuration changes via the setRetainInstance(true) method call.

For example, if you define an AsyncTask as field in a headless fragment, it can continue to run during configuration changs.

Источник

Процессы и потоки в Android: пишем AsyncTask правильно

Продолжаю свои повествования об Android. И в этот раз хочу поделиться ценной информацией о процессах и потоках, которая должна быть хорошо усвоена и всегда оставаться под рукой во избежании ошибок и недопонимания при написании приложений. В конце статьи приведу пример реализации AsyncTask, который загружает в ImageView картинку по нажатию на кнопку.

Прежде всего отмечу, что подробнее о данной теме можно прочесть в данном руководстве — developer.android.com/guide/topics/fundamentals/processes-and-threads.html

На заметку о процессах и потоках в Android

Когда запускается компонент приложения и приложение не имеет других запущенных компонентов, Android создает новый процесс для приложения с одним потоком исполнения. По умолчанию все компоненты одного приложения запускаются в одном процессе, в потоке называемом «главный». Если компонент приложения запускается и уже существует процесс для данного приложения(какой-то компонент из приложения существует), тогда компонент запущен в этом процессе и использует его поток выполнения. Вы можете изменить данное поведение, задав разные процессы для разных компонентов вашего приложения. Кроме того вы можете добавить потоки в любой процесс.

Задать отдельный процесс для компонента можно с помощью файла манифеста. Каждый тег компонента(activity, service, receiver и provider) поддерживает атрибут android:process. Данный атрибут позволяет задать процесс, в котором будет выполняться компонент. Также вы можете задать процесс в котором будут выполняться компоненты разных приложений. Также данный атрибут поддерживается тегом application, что позволяет задать определенный процесс для всех компонентов приложения.

Android пытается поддерживать процесс приложения как можно дольше, но когда потребуются ресурсы старые процессы будут вытеснены по иерархии важности.

Существует 5 уровней иерархии важности: (процессы первого уровня из списка будут удалены последними)

1.Процесс с которым взаимодействует пользователь(Foreground process)
К таким процессам относится например: активити с которым взаимодействует пользовать; сервис(экземпляр Service), с которым взаимодействует пользователь; сервис запущенный методом startForeground(); сервис, который выполняет один из методов своего жизненного цикла; BroadcastReceiver который выполняет метод onReceive().

2.Видимый процесс
Процесс, в котором не выполнены условия из пункта №1, но который влияет на то, что пользователь видит на экране. К примеру, вызван метод onPause() активити.

Читайте также:  Андроид не ловит все wi fi

3.Сервисный процесс
Служба запущенная методом startService()

4.Фоновый процесс
Процесс выполняемый в фоновом режиме, который невиден пользователю.

Отмечу, что в компонентах приложения существует метод onLowMemory(), но полагаться на то, что данный метод будет вызван нельзя, также как нельзя на 100% полагаться на метод onDestroy(), поэтому логику сохранения данных или каких-либо настроек можно осуществить в методе onStop(), который(как уверяют) точно вызывается.

Когда запускается приложение, система создает «главный» поток выполнения для данного приложения, который также называется UI-потоком. Этот поток очень важен, так как именно в нем происходит отрисовка виджетов(кнопочек, списков), обработка событий вашего приложения. Система не создает отдельный поток для каждого экземпляра компонента. Все компоненты, которые запущенны в одном процессе будут созданы в потоке UI. Библиотека пользовательского интерфейса Android не является потоково-безопасной, поэтому необходимо соблюдать два важных правила:

1) Не блокировать поток UI
2) Не обращаться к компонентам пользовательского интерфейса не из UI-потока

Теперь, предположим, что у нас возникла задача — загрузить картину в ImageView из сети и тут же ее отобразить. Как мы поступим? По логике: мы создадим отдельный поток, который и сделает всю нашу работу, примерно так:

Выглядит правдоподобно, так как мы вынесли операцию загрузки картинки в отдельный поток. Проблема в том, что мы нарушили правило №2. Исправить эту проблему можно с помощью следующих методов:

Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)

К примеру, воспользуемся первым из них:

Теперь реализация потоково-безопасная: сетевая операция выполняется в отдельном потоке, а к ImageView обращаемся из потока UI.
К счастью, данные операции можно объединить с помощью наследования класса Handler и реализации нужной логики, но лучшее решение — наследовать класс AsyncTask.

AsyncTask позволяет выполнить асинхронную работу и делать обновления пользовательского интерфейса.
Для обновления реализуйте метод onPostExecute(), а всю фоновую работу заключите в метод doInBackground(). После того, как вы реализуете свою собственную задачу, необходимо ее запустить методом execute().

Привожу обещанный пример AsyncTask, в котором реализована задача загрузки и отображения картинки(вариант с аннотациями и отклонением от применения стандартного протокола диалогов):

А теперь рассмотрим самый правильный вариант с точки зрения работы с диалогами:

Кода стало побольше, но лучше использовать стандартный протокол работы с диалогами.
Также я убрал все аннотации, чтобы новичкам было проще попробовать данный код.

Не забудьте добавить в свою разметку кнопочки атрибут с указанным значением: android:onClick=«runButtonHandler»

И добавлю: в оффициальном документе(Тыц ) также, как и в моем случае, не используется preExecute(), но если вам понадобится выполнить какие-то действия с вашим пользовательским интерфейсом до начала выполнения задачи, то смело используйте данный метод.

Параметры передаваемые в AsyncTask:
1. Параметры(в нашем случае адрес URL).
2. Прогресс (единицы задающие ход изменения задачи). В нашем случае не используется.
3. Результат выполнения задачи(в нашем случае объект Bitmap)

Код довольно прост: всю фоновую работу мы выполняем в методе doInBackGround(), вызывая метод publishProgress(), чтобы во время загрузки картинки крутился наш ProgressDialog при вызове метода onProgressUpdate(). После выполнения фоновой работы вызывается метод onPostExecute() в который передается результат работы метода doInBackGround(), в нашем случае это объект Bitmap и тут же мы его загружаем в ImageView.
Отмечу пару важных моментов, которые нужно учитывать:

1) Метод doInBackGround() выполняется в фоновом потоке, потому доступа к потоку UI внутри данного метода нет.
2) Методы onPostExecute() и onProgressUpdate() выполняются в потоке UI, потому мы можем смело обращаться к нашим компонентам UI.

Да, я снова применил библиотеку android-annotations, так что не пугайтесь аннотациям.

Хочу отметить важность понимания модели работы процессов в Android, чтобы не допустить ошибок при разработке приложений.

Данная статья это переработка доступной информации + личный опыт при реализации указанной задачи и работе с потоками.

Как всегда пожелания и замечания по поводу материала статьи в личку. Если вам есть что-то добавить или дополнить — смело пишите в комментарии.

UPD Статья обновленна добавлением более правильной версии в плане работы с диалогами.

Источник

Руководство по фоновой работе в Android. Часть 1

О фоновой работе приложений в Android есть много статей, но мне не удалось найти подробного руководства по реализации работы в фоне – думаю, из-за того, что появляется все больше новых инструментов для такой работы. Поэтому я решил написать серию статей о принципах, инструментах и методах асинхронной работы в приложениях под Android.

Будет несколько частей:

  1. Основной поток, осуществление фоновой работы с помощью AsyncTask, публикация результатов в основном потоке.
  2. Затруднения при использовании AsyncTask. Loaders как один из способов их избежать.
  3. Работа в фоне с помощью ThreadPools и EventBus.
  4. RxJava 2 как метод асинхронной работы.
  5. Корутины в Kotlin как метод асинхронной работы.
Читайте также:  Word для android планшет

Начнем с первой части.

Основы UI

Первое, что следует понять, – почему мы вообще беспокоимся о работе в фоне в мобильных приложениях.

Во всех приложениях для Android есть хотя бы один поток, на котором происходит прорисовка UI и обработка пользовательского ввода. Поэтому он и называется потоком UI или главным потоком.

Каждый метод жизненного цикла каждого компонента вашего приложения, включая Activity, Service и BroadcastReceiver, исполняется на UI-потоке.

Человеческий глаз преобразовывает сменяющиеся изображения в плавное видео, если частота смены достигает 60 кадров в секунду (да, это магическое число берется отсюда), давая основному потоку только 16 мc для прорисовки всего экрана.

Продолжительность сетевого вызова может быть в тысячи раз больше.

Когда мы хотим загрузить что-либо из Интернета (прогноз погоды, пробки, сколько стоит ваша часть биткоина в данный момент), мы не должны делать это из главного потока. Более того, Android не позволит нам, выбросив NetworkOnMainThreadException.

Семь лет назад, когда я разрабатывал свои первые приложения на Android, подход от Google был ограничен использованием AsyncTasks. Давайте посмотрим, как мы писали код для общения с сервером (псевдокод преимущественно):

Метод doInBackground() гарантированно будет вызван не на основном потоке. Но на каком? Зависит от реализации. Вот как Android выбирает поток (это часть исходного кода класса AsyncTask):

Здесь можно увидеть, что выполнение зависит от параметра Executor. Посмотрим, откуда он берется:

Как здесь указано, по умолчанию executor ссылается на пул потоков размера 1. Это означает, что все AsyncTasks в вашем приложении запускаются последовательно. Это не всегда было верно, так как для версий ОС от DONUT до HONEYCOMB использовался пул размером от 2 до 4(в зависимости от количества ядер процессора). После HONEYCOMB AsyncTasks снова выполняются последовательно по умолчанию.

Итак, работа выполнена, байты закончили свое длинное путешествие с другого полушария. Нужно превратить их во что-то понятное и разместить на экране. К счастью, наша Activity тут как тут. Давайте поместим результат в одно из наших View.

О, черт! Опять исключение!

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Но мы не делали никаких сетевых обращений на основном потоке! Правильно, но мы попытались нарушить другой закон UI. Пользовательский интерфейс можно менять только из UI-потока. Это верно не только для Android, но и практически для любой системы, с которой вы столкнетесь. Причину этого хорошо объяснили в Java Concurrency In Practice. Вкратце – архитекторы хотели избежать сложной блокировки при изменениях из нескольких источников (пользовательский ввод, биндинг и другие изменения). Использование единственного потока решает эту проблему.

Да, но UI все равно нужно обновлять. У AsyncTask есть еще метод onPostExecute, который вызывается на UI-потоке:

Как эта магия работает? Посмотрим в исходном коде AsyncTask:

AsyncTask использует Handler для вызова onPostExecute в UI, ровно как и метод postOnUiThread в компонентах Android.

Handler прячет всю внутреннюю кухню. Какую именно? Идея состоит в том, чтобы иметь бесконечный цикл проверки сообщений, приходящих на UI-поток, и обрабатывать их соответствующе. Велосипедов тут никто не изобретает, хотя без кручения педалей не обошлось.

Для Android это реализовано классом Looper, который передается в InternalHandler в приведенном выше коде. Суть класса Looper находится в методе loop:

Он просто опрашивает очередь входящих сообщений в бесконечном цикле и обрабатывает эти сообщения. Это означает, что на UI-потоке должен быть инициализированный экземпляр Looper. Можно получить доступ к нему с помощью статического метода:

Кстати, вы только что узнали, как проверить, вызывается ли ваш код в UI-потоке:

Если вы попытаетесь создать экземпляр Handler в методе doInBackground, то получите другое исключение. Оно сообщит о необходимости наличия Looper для потока. Теперь вы знаете, что это значит.

Надо заметить, что AsyncTask может быть создан только в UI-потоке по указанным выше причинам.
Вы можете подумать, что AsyncTask – это удобный способ выполнения фоновой работы, так как он скрывает сложность и требует немного усилий при использовании, но есть несколько проблем, которые приходится решать по пути:

  • Каждый раз нужно писать достаточно много кода для решения относительно простой задачи
  • AsyncTasks ничего не знают о жизненном цикле. При неправильном обращении лучшее, что вы получите — утечка памяти, в худшем – сбой
  • AsyncTask не поддерживает сохранение состояния прогресса и повторное использование результатов загрузки.

В следующей части я подробно разберу эти проблемы и покажу, как Loaders могут помочь их решить.

Источник

Оцените статью