- PVSM.RU - https://www.pvsm.ru -

Android O and background services

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

Темой данной публикации будут изменения в Android Oreo. Вы можете почитать подробнее здесь [1]. Все статьи которые я находил, с возможным вариантом решения проблем говорили «Просто наследуй сервис от JobIntentService [2] и используй его в 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() или необходимый метод вашего сервиса).

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

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

//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
Пример можно найти здесь [4]
И возвращаясь к теме того с чего я начал «Первым таким сложным изменением были -Runtime permissions», можете так же оценить мой вариант [5] решения этой проблемы.

Автор: Euzee

Источник [6]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/android/266828

Ссылки в тексте:

[1] здесь: https://developer.android.com/about/versions/oreo/android-8.0-changes.html#all-apps

[2] JobIntentService: https://developer.android.com/reference/android/support/v4/app/JobIntentService.html

[3] здесь: https://github.com/Euzee/serviceManager

[4] здесь: https://github.com/Euzee/serviceManagerExample

[5] мой вариант: https://github.com/Euzee/permissionUtil

[6] Источник: https://habrahabr.ru/post/341106/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox