- PVSM.RU - https://www.pvsm.ru -
Всем привет.
Как и большенству разработчиков — мне было лень делать сложные изменения от версии к версии Андроида. Первым таким сложным изменением были -«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
Нажмите здесь для печати.