В этой статье мы рассмотрим важный компонент в разработке приложений Android — Android Service. В отличие от Activity, Service работает в фоновом режиме в Android. У Service нет пользовательского интерфейса, и его жизненный цикл также отличается от жизненного цикла Activity. Используя Service, мы можем выполнять некоторые фоновые операции, например загружать веб-страницу с удаленного сервера. Мы можем использовать Service для реализации многозадачности в Android.
Обзор Android Service
Мы знаем, что если системные ресурсы становятся ограниченными, Android Activity может быть запущена, остановлена, уничтожена или даже пересоздана. Service, напротив, спроектирован так, чтобы иметь более длительный жизненный цикл. Service в Android может быть запущен из Activity, Broadcast receiver или из других Service.
Следует отметить, что использование Service не создает автоматически новый поток. Поэтому, если мы хотим реализовать в Service простую логику, не требующую длительной обработки, нам не нужно запускать ее в отдельном потоке. Однако, если нам нужно реализовать сложную логику, обработка которой занимает много времени, нужно быть осторожными при создании новых потоков; в противном случае, поскольку Service работает в главном потоке, это может вызвать проблемы ANR (Application Not Responding).
Основные сценарии использования Service в Android следующие:
- Реализация многозадачности (multi-task)
- Межпроцессное взаимодействие (IPC)
Типичный пример первого случая — когда приложению нужно загрузить данные с удаленного сервера. В этом случае можно использовать Activity, который взаимодействует с пользователем, и запустить Service, пока пользователь пользуется приложением, позволяя ему завершить работу в фоне. Есть также сценарий, в котором Service отправляет информацию пользователю после выполнения своей задачи.
Во втором случае мы хотим "поделиться" некоторой общей функциональностью, чтобы разные приложения могли повторно ее использовать. Например, предположим, у нас есть Service, который может отправлять электронные письма, и мы хотим совместно использовать этот Service в нескольких приложениях, чтобы не переписывать один и тот же код. В этом случае мы можем использовать IPC, чтобы Service предоставлял "удаленный" интерфейс, который могут вызывать другие приложения.
Основы Service
Теперь, когда мы лучше понимаем Service, давайте создадим его. Чтобы создать Service в Android, нам нужно наследоваться от класса Service.
public class TestService extends Service {
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Как видите, мы реализовали только метод под названием onBind. В примере выше мы использовали локальный Service, поэтому метод возвращает null. Как упоминалось ранее, у Service есть собственный жизненный цикл, поэтому мы можем переопределить некоторые callback-методы для обработки его различных состояний:
public class TestService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Первый метод, onCreate, вызывается только при создании Service. Если Service уже запущен, этот метод не будет вызван. Мы не можем вызвать его напрямую; он вызывается системой.
Метод onStartCommand — самый важный метод, потому что он вызывается, когда нам нужно запустить Service. В этот метод передаётся Intent, который был передан при запуске Service, поэтому мы можем обмениваться некоторой информацией с Service. В этом методе мы реализуем собственную логику: если это не длительная операция, её можно выполнить прямо в этом методе; в противном случае можно создать поток. Как видите, этот метод должен возвращать целочисленное значение. Это целое число определяет, как система должна обрабатывать Service:
- START_STICKY: С этим возвращаемым значением, если система уничтожит наш Service, он будет создан заново. Однако Intent, отправленный в Service, не будет доставлен повторно. Таким образом Service продолжает работать.
- START_NOT_STICKY: Если система уничтожит Service, он не будет создан заново, если только клиент явно не вызовет команду onStart.
- START_REDELIVER_INTENT: Работает аналогично START_STICKY. Кроме того, в этом случае Intent будет доставлен в Service повторно.
onDestroy — это метод, вызываемый системой, когда Service собирается быть уничтоженным.
После того как у нас есть пользовательский класс Service, нам нужно объявить его в Manifest.xml, чтобы мы могли его использовать.
<service android:name=".TestService"
android:enabled="true"/>
Запуск и остановка Service
Как мы знаем, Service запускается и в конечном итоге останавливается, чтобы он мог завершить свою задачу. Предположим, мы запускаем его из Activity; мы можем использовать Intent, чтобы передать некоторую информацию в Service. Предположим, в нашем Activity есть две кнопки: одна для запуска, а другая для остановки Service:
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this, TestService.class);
i.putExtra("name", "SurvivingwithAndroid");
MainActivity.this.startService(i);
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this, TestService.class);
MainActivity.this.stopService(i);
}
});
В строке 5 примера кода выше мы создаём Intent, который передаёт имя класса для обработки нашего Service, и задаём некоторые параметры, такие как name. Затем в строке 7 мы запускаем этот Service. Таким же образом в строке 17 мы останавливаем этот Service.

Когда вы нажимаете кнопку запуска, вы получаете следующий Log:

Можно заметить, что вызывается метод onCreate. Потому что это первый раз, когда мы запускаем этот Service. Если мы снова нажмём кнопку запуска, система не вызовет onCreate. Когда мы нажмём кнопку остановки, система уничтожает этот Service.
IntentService
Как мы упоминали ранее, Service выполняется в основном потоке. Поэтому нужно быть очень осторожными при реализации логики в Service. Учтите, что если эта логика является блокирующей операцией или требует много времени для завершения, это может привести к проблемам ANR. В таких случаях нам нужно переместить логику в отдельный поток. Это означает создание потока в методе onStartCommand и последующий его запуск.
Ещё один класс, производный от Service, — IntentService — может упростить нашу разработку. Этот класс полезен, когда нам не нужно обрабатывать несколько запросов одновременно. Он создаёт рабочий поток для обработки разных запросов. Выполняемые операции таковы:
- Создаёт отдельный поток для обработки запросов.
- Создаёт очередь запросов и время от времени передаёт в неё Intent.
- Создаёт реализацию onStartCommand по умолчанию.
- Останавливает Service после выполнения всех запросов.
Если мы хотим создать IntentService, нам нужно наследоваться от класса IntentService, а не от класса Service:
public class TestIntentService extends IntentService {
public TestIntentService() {
super("TestIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
}
}
В этом примере нам нужно реализовать только метод onHandleIntent. Внешней логике, реализуемой здесь, не нужно беспокоиться о том, является ли операция длительной, потому что этот метод вызывается в отдельном потоке.
Автоматический запуск Service
Часто мы хотим запускать наш Service автоматически, например, автоматически запускать его при загрузке. Мы знаем, что для запуска Service нужен компонент. Так как же сделать это автоматически? Мы можем использовать broadcast receiver, чтобы запустить Service. Например, если мы хотим запустить его при загрузке смартфона, мы можем сначала создать broadcast receiver, который прослушивает это событие (boot), а затем запустить Service.
public class BootBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
ctx.startService(new Intent(ctx, TestService.class));
}
}
Объявите его в Manifest.xml:
<receiver android:name=".BootBroadcast">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Источник: http://www.importnew.com/9019.html