Android O and background services

в 14:55, , рубрики: android, Android O, background, service, support, Разработка под android

Всем привет.
Как и большенству разработчиков — мне было лень делать сложные изменения от версии к версии Андроида. Первым таким сложным изменением были -«Runtime permissions», которые пришли к нам с 6-м андроидом. Но это уже в прошлом.

Темой данной публикации будут изменения в Android Oreo. Вы можете почитать подробнее здесь. Все статьи которые я находил, с возможным вариантом решения проблем говорили «Просто наследуй сервис от JobIntentService и используй его в enqueueWork()».

Круто, да. Но не все так просто. Если заглянуть в CommandProcessor, то можно увидеть что сервис останавливается сразу после выполнения onHandleWork(). Это происходит потому, что IntentService не предназначем на выполнения сложных работ, он создан для вещей вроде: доставки ивентов, старта прочих сервисов и так далее.

while ((work = dequeueWork()) != null) {
    if (DEBUG) Log.d(TAG, "Processing next work: " + work);
    onHandleWork(work.getIntent());
    if (DEBUG) Log.d(TAG, "Completing work: " + work);
    work.complete();
}
//Work
@Override
public void complete() {
    if (DEBUG) Log.d(TAG, "Stopping self: #" + mStartId);
    stopSelf(mStartId);
}

Эти статьи и их решения ничем мне не помогли, так как они просто копия с developer.android.com. По этому я продолжил тестировать и искать простые варианты использования сервисов пока приложение в фоне ( в совместимости с Android O). И я нашел способ.

Используя JobIntentService можно попробовать запустить ваш сервис по старинке, но контекст предоставляемый JobIntentService не подходит для этих целей, но мы всегда можем запросить контекст приложения. Но даже когда у нас будет контекст приложения, при старте сервиса нас остановят ограничения андроида.

Что же дальше? Эти ограничения на фоновое выполнение работают только тогда, когда вы пытаетесь запустить сервис с помошью startService(), если же вы будете использовать bindService, то никаких ошибок вам андроид не выдаст. Но, в случае байнда сервис будет только создан и прикреплен к приложению и нужно это все делать вместе с созданием и реализацией ServiceConnection, по вызову которого необходимо запустить необходимый метод ( onHandleWork() или onHandleIntent() или необходимый метод вашего сервиса).

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

И небольшой пример с гита:

//No need to create classes and add manifest declarations

ServiceManager.runService(context, () -> {Logg.e(TAG,"Some Action");},true);

//if you have already prepared service you can us it as :
ServiceManager.runService(context, GeofenceTransitionsIntentService.class);

//or if you need to add some data or actions you can use it like :
 Intent geo = new Intent(context, GeofenceTransitionsIntentService.class);
 geo.setAction(GeofenceTransitionsIntentService.ACTION_REQUEST_LOCATIONS);
 ServiceManager.runService(context, geo);

Для того чтобы использовать 2 последних варианта — нужно пронаследовать CompatService
Пример можно найти здесь
И возвращаясь к теме того с чего я начал «Первым таким сложным изменением были -Runtime permissions», можете так же оценить мой вариант решения этой проблемы.

Автор: Euzee

Источник

Поделиться

* - обязательные к заполнению поля