Android - внедрение startForeground для службы?

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

Intent i = new Intent(context, myService.class); 
context.startService(i);

А затем в onCreate () myServices я пробую startForeground () ...?

Notification notification = new Notification();
startForeground(1, notification);

Так что да, я немного потерялся и не знаю, как это реализовать.


person JDS    schedule 18.06.2011    source источник
comment
Что ж, это не работает, по крайней мере, насколько я могу судить, моя служба по-прежнему работает как фоновая и перестает работать.   -  person JDS    schedule 18.06.2011
comment
Тема связана с: stackoverflow.com/questions/10962418 /   -  person Snicolas    schedule 12.10.2012


Ответы (11)


Я бы начал с полного заполнения Notification. Вот пример проекта, демонстрирующий использование startForeground().

person CommonsWare    schedule 18.06.2011
comment
Можно ли использовать startForeground () без уведомления? Или мы можем позже обновить такое же уведомление? - person JRC; 09.01.2012
comment
Есть ли конкретная причина, по которой вы использовали 1337? - person Cody; 17.02.2012
comment
@DoctorOreo: он должен быть уникальным в приложении, но не обязательно уникальным на устройстве. Я выбрал 1337, потому что это 1337. :-) - person CommonsWare; 17.02.2012
comment
@JRC вопрос хороший. Можно ли использовать startForeground () без уведомления? - person Snicolas; 12.10.2012
comment
@Snicolas: Спасибо, что указали на недостаток в Android. Я буду работать над тем, чтобы это исправить. - person CommonsWare; 12.10.2012
comment
На самом деле, это может быть интересный механизм. Конечно, это может привести к очень плохой практике размещения служб на переднем плане без уведомления пользователя, но это также может быть удобно. Под этим я подразумеваю, что очень сложно управлять службой в Android, которая запускается и связана различными действиями. Если служба не может получить доступ к переднему плану, она уничтожается и воссоздается после каждой операции отмены привязки. Это не задокументировано (я считаю) и просто делает невозможным использование какой-либо стабильной службы путем привязки. Хорошим исправлением было бы разрешить это или нет через разрешение. - person Snicolas; 12.10.2012
comment
@Snicolas: если служба не может получить доступ к переднему плану, она уничтожается и воссоздается после каждой операции отмены привязки. - Я не знаю, что передний план как-то влияет на это. Если это действительно так, это тоже может быть ошибкой. - person CommonsWare; 12.10.2012
comment
@CommonsWare, я говорил себе, что, возможно, запрашивал функцию для обхода ошибки. Но если тихая внешняя служба запрещена, то мне бы очень хотелось, чтобы тот же выпуск явно предоставлял способ получить службу, поддерживающую смешанный жизненный цикл (привязанный и запущенный). Я считаю, что эта услуга очень важна, и я склонен полагать, что многие люди тоже этого ждут ''. - person Snicolas; 12.10.2012
comment
@Snicolas: сервис, поддерживающий смешанный жизненный цикл (связанный и запущенный) - хотя я никогда этого не делал, похоже, что у многих других разработчиков нет проблем с использованием как startService(), так и bindService(). - person CommonsWare; 12.10.2012
comment
Я видел несколько тем на SOF. Но еще вопрос? Как сервис может выжить в моем приложении, если не на переднем плане? Я имею в виду выжить, когда убиваю приложение с помощью переключателя задач. Да, и сервис в том же процессе, что и приложение. - person Snicolas; 13.10.2012
comment
@Snicolas: Ни одна служба не выживает, будучи убитой убийцей задач, независимо от того, находится ли ваша служба на переднем плане или нет. - person CommonsWare; 13.10.2012
comment
@CommonsWare Не убийца задач, а удобный для пользователя переключатель задач, обеспечиваемый долгим нажатием кнопки «Домой» (я полагаю, над HoneyComb, но, возможно, ICS). - person Snicolas; 14.10.2012
comment
@Snicolas: Ваш сервис не будет немедленно затронут действиями другого приложения, выходящими на передний план, ни в коем случае. - person CommonsWare; 14.10.2012
comment
@CommonsWare Я рад, что мы поговорим об этом, но на самом деле мы не в теме. Могу ли я связаться с вами напрямую? Я не имел в виду, что переключение на новую задачу может повлиять на мое приложение, я говорил об использовании переключателя задач, чтобы убить приложение (сдвигая его вправо), что является более удобным для пользователя способом убить приложение, чем использование меню приложений в настройках приложение телефона Android (хотя оба способа не имеют одинакового воздействия). - person Snicolas; 14.10.2012
comment
@CommonsWare Я понимаю, что это старое обсуждение, но в проекте, на который указывает ссылка выше, FakePlayer, ни FakePlayer.java, ни PlayerService.java не имеют метода с именем startForeground(). Я что-то упускаю? Я новичок в сервисах и пытаюсь учиться, играя с фрагментами кода. Спасибо. - person aLearner; 29.12.2012
comment
@CommonsWare Чтобы добавить к тому, что я написал, я также заметил, что служба запускается нормально, но если я открываю много (ресурсоемких) приложений, а затем нажимаю кнопку домой (чтобы не уничтожать их), я вижу следующие три строки в LogCat, после которого служба кажется умирает (поскольку я не вижу ее под Menu --> Manage apps --> Running - как это было раньше). Обратите внимание, что время и дата удалены для краткости. [1] D/ActivityThread(3487): setTargetHeapUtilization:0.25 [2] D/ActivityThread(3487): setTargetHeapIdealFree:8388608 [3] D/ActivityThread(3487): setTargetHeapConcurrentStart:2097152 - person aLearner; 29.12.2012
comment
@aLearner: PlayerService вызывает startForeground(), строка 70. И я понятия не имею, что означают эти сообщения журнала. - person CommonsWare; 29.12.2012
comment
@CommonsWare: Спасибо. Я не вижу строки 70. В файле PlayerService.java, который я просматриваю, всего 62 строки. Спасибо еще раз. - person aLearner; 29.12.2012
comment
@aLearner: github.com/commonsguy/cw-android/blob/master/Notifications/ содержит 81 строку. - person CommonsWare; 29.12.2012
comment
@CommonsWare Верно. Большое тебе спасибо. Не знаю, как у меня получился 62-строчный PlayerService.java файл. Оба раза я заходил: github.com/commonsguy/cw-android и нажимал ZIP. Я нашел проект под Notifications --> FakePlayer\ --> src --> com --> commonsware --> android --> fakeplayerfg (fakeplayer). Во всяком случае, я скачал все заново, и сейчас действительно вижу 81 строку. Файл PlayerService.java, который у меня есть, имеет отметку даты 13 февраля 2012 г., а более новый, который я скачал, имеет отметку даты 30 декабря 2012 г. - так что, возможно, было обновление. Еще раз спасибо за вашу помощь. - person aLearner; 30.12.2012
comment
@CommonsWare Я наконец понял это. Ссылки, которыми вы поделились, указывают на .../Notifications/FakePlayer. Однако существует еще один проект с таким же названием в .../Service/FakePlayer. Это то, что меня сбило с толку, особенно после того, как я загрузил все проекты в виде файла ZIP, а затем перешел в папку Service вместо папки Notifications. Уф! - person aLearner; 01.01.2013
comment
@CommonsWare, более чем через год, в JB была исправлена ​​уязвимость отображения уведомления с нулевым значком. Кстати, это довольно впечатляюще. Спасибо, Марк, в RoboSpice мы фактически завершаем новую реализацию наших сервисов, которые сделают наши сервисы сверхчистыми в этом отношении: наши сервисы будут выходить на передний план только тогда, когда они не связаны и им есть чем заняться, и в этом случае только отобразит уведомление переднего плана. Вы способствовали исправлению этой уязвимости? - person Snicolas; 17.08.2013
comment
@Snicolas: это сделает наши сервисы сверхчистыми в этом отношении: наши сервисы будут отображаться на переднем плане только тогда, когда они не связаны и им есть чем заняться, и в этом случае будет отображаться только уведомление переднего плана - это было бы необычно чудесно. Вы способствовали исправлению этой уязвимости? - Я подал вопрос по этому поводу. Поскольку проблема так и не была принята, я бы предположил, что это не повлияло на нее. - person CommonsWare; 17.08.2013
comment
@CommonsWare. Хммм, я предпочитаю верить, что ты ему помог. И, может быть, я в меньшей степени. Нам нужен какой-то личный миф, не так ли? :) Что ж, прежде чем мы снова встретимся на DroidCon London / Anddev, не могли бы вы попробовать RoboSpice? :) - person Snicolas; 17.08.2013
comment
@Snicolas: Когда-нибудь, возможно, но у меня есть длинный список дел. - person CommonsWare; 17.08.2013
comment
Реализация Notification устарела. Я бы выбрал другой высоко оцененный ответ. - person OneWorld; 22.03.2017
comment
@OneWorld: Единственные другие ответы на этот вопрос демонстрируют то, что я имею в виду в своем ответе. - person CommonsWare; 22.03.2017
comment
Это очень старый поток, но я хотел бы спросить, применимо ли превращение сервиса в сервис переднего плана как для сервиса, так и для IntentService (на котором основан ваш пример проекта). - person RenniePet; 29.04.2017
comment
@RenniePet: Во всяком случае, это больше применимо к обычному Service. Это действительно зависит от того, что делает сервис. - person CommonsWare; 29.04.2017
comment
@CommonsWare Глядя на образец на Github, не следует ли нам использовать новый startForegroundService Android O? - person android developer; 16.01.2018
comment
@androiddeveloper: в этом нет необходимости, поскольку служба запускается на переднем плане. startBackgroundService() необходим, если ваш код по той или иной причине уже находится в фоновом режиме и ему необходимо запустить службу. При этом вы также можете использовать его на переднем плане. - person CommonsWare; 16.01.2018
comment
@CommonsWare Зачем нужна эта дифференциация, если она может делать то же самое, что и до Android O? Кроме того, это startForegroundService ... - person android developer; 16.01.2018
comment
@androiddeveloper: потому что иногда ваше приложение уже находится в фоновом режиме, когда вам нужно запустить службу переднего плана, например, получив широковещательную рассылку. Также извините за опечатку. - person CommonsWare; 16.01.2018
comment
@CommonsWare Я не понимаю. Так что, если он в фоновом режиме? Даже в этом случае можно запустить службу на переднем плане. Что дает такая дифференциация? - person android developer; 16.01.2018
comment
@androiddeveloper: даже в этом случае можно запустить службу на переднем плане - нет, нельзя. См. документацию. - person CommonsWare; 16.01.2018
comment
@CommonsWare Я не понимаю. Предположим, я создаю приложение, которое, как и приложение «Будильник», открывается в определенное время (или другой глобальный триггер). Я не могу создать службу переднего плана перед отображением Activity? - person android developer; 16.01.2018
comment
@androiddeveloper: вы можете через startForegroundService() на Context или getForegroundService() на PendingIntent. - person CommonsWare; 16.01.2018
comment
@CommonsWare Итак, как я уже писал, все еще возможно, как и раньше, создать службу переднего плана во всех случаях, независимо от того, находится ли ваше приложение в фоновом или на переднем плане, нет? - person android developer; 16.01.2018
comment
@androiddeveloper: это возможно, если вы выберете правильный метод, как я писал. - person CommonsWare; 16.01.2018
comment
@CommonsWare Это был вопрос: зачем нужна эта дополнительная функция, если бы мы могли сделать то же самое раньше ... Я думаю, что они сделали это только потому, что они позволяют открывать только службы переднего плана, когда приложение находится в фоновом режиме : С Android 8.0 есть сложности; система не позволяет фоновому приложению создавать фоновую службу. По этой причине в Android 8.0 представлен новый метод startForegroundService () для запуска новой службы на переднем плане. . Просто чтобы напомнить нам, что новый сервис должен стать сервисом на переднем плане довольно скоро, если мы хотим, чтобы он оставался дольше. - person android developer; 16.01.2018
comment
@androiddeveloper: ИМХО, это не просто напоминание. Если вы попытаетесь вызвать startService() в фоновом режиме, это не поможет на Android 8.0+. Ничего из этого изменения не включает новые функции. Он просто предоставляет возможности для поддержания существующей функциональности, если она соответствует рекомендациям. - person CommonsWare; 16.01.2018
comment
@CommonsWare Это терпит неудачу, потому что им нужна служба переднего плана. Интересно, однако, что произойдет, если вы воспользуетесь startForegroundService, но вскоре после этого не превратите его в настоящую службу переднего плана. Он рухнет или сделает что-нибудь еще? И означает ли это, что в этом небольшом временном окне можно использовать фоновую службу? - person android developer; 16.01.2018
comment
@androiddeveloper: он вылетит или сделает что-нибудь еще? - да, после периода ANR. И означает ли это, что в этом небольшом временном окне можно использовать фоновую службу? - если вы не против разбиться, то да. У вас сбой, даже если вы остановите службу, если вы не позвонили startForeground(). Это серьезно отягощает. - person CommonsWare; 16.01.2018
comment
@CommonsWare Не уверен, что понимаю. Вы имеете в виду, что он выйдет из строя, что бы я ни делал, если я не позвоню startForeground? Например, если я начну там новый поток, который выполняет очень короткую работу (скажем, 2 секунды), а затем я решу остановить службу, она все равно выйдет из строя? - person android developer; 16.01.2018
comment
@androiddeveloper: да, по обоим пунктам. - person CommonsWare; 16.01.2018
comment
@CommonsWare Интересно. Считается ли приложение фоном в следующем случае (я хочу это проверить): пользователь видит действие приложения и нажимает клавишу «Домой» (вместо этого теперь видит панель запуска)? - person android developer; 16.01.2018
comment
@androiddeveloper: Да, по истечении минутного льготного периода. Если у вас есть дополнительные проблемы в этой области, задайте отдельный вопрос о переполнении стека, вместо того, чтобы продолжать связывать все больше и больше комментариев по этому несвязанному ответу. - person CommonsWare; 16.01.2018
comment
@CommonsWare Я пытаюсь создать сервис, который может запускать или останавливать только пользователь. Прямо сейчас я запускаю передний план из onstartcommand, но когда я закрываю приложение, служба останавливается примерно через 15-20 минут, и уведомление исчезает. Есть ли у вас что-нибудь на GitHub, где только пользователь может запускать или останавливать службу? - person JRowan; 26.03.2019
comment
Вот услуга, о которой я говорю, если вы хотите взглянуть на github.com/copypasteearth/Powerball-MegaMillions/blob/master/ - person JRowan; 26.03.2019
comment
@JRowan: Я пытаюсь создать сервис, который может запускать или останавливать только пользователь - извините, но я не знаю, что вы имеете в виду. Вы можете подумать о том, чтобы задать отдельный вопрос о переполнении стека, где вы сможете более подробно объяснить свои проблемы. - person CommonsWare; 27.03.2019
comment
служба переднего плана без уведомления, как показать - person Harsha; 28.04.2020
comment
@Harsha: Извините, но это недоступно. - person CommonsWare; 28.04.2020

Из вашего основного действия запустите службу с помощью следующего кода:

Intent i = new Intent(context, MyService.class); 
context.startService(i);

Затем в своем сервисе для onCreate() вы должны создать свое уведомление и установить его как передний план, например:

Intent notificationIntent = new Intent(this, MainActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, 0);

Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.app_icon)
                .setContentTitle("My Awesome App")
                .setContentText("Doing some work...")
                .setContentIntent(pendingIntent).build();

startForeground(1337, notification);
person mikebertiean    schedule 15.03.2016
comment
@mike как обновить это уведомление от MainActivity? - person Roon13; 15.09.2017
comment
@ Roon13 с использованием идентификатора, в данном случае 1337 ... вы должны иметь возможность создать новое уведомление и вызвать startForeground с идентификатором - person mikebertiean; 15.09.2017
comment
@ Roon13 ознакомьтесь с этим вопросом stackoverflow.com/questions/5528288/ - person mikebertiean; 15.09.2017
comment
@mikebertiean Как я могу вызвать startForeground из MainActivity? также как я могу очистить уведомление от MainActvity, когда процесс будет завершен? - person Roon13; 15.09.2017
comment
@mikebertiean Я понял, что мне нужно снова вызвать startForeground в классе обслуживания, но как? Нужно ли мне снова вызывать startService ()? - person Roon13; 15.09.2017
comment
@mikebertiean, неважно, я использовал диспетчер уведомлений для обновления уведомлений от MainActivity. Это сработало. - person Roon13; 15.09.2017
comment
NotificationCompat.builder (context) устарел. Теперь вам нужно включить идентификатор смены - NotificationCompat.builder (context, channelId). - person A.J.; 23.02.2018
comment
Не забывайте: ‹использует-разрешение android: name = android.permission.FOREGROUND_SERVICE /› - person Reeman Adel; 22.03.2020

Решение для Oreo 8.1

Я столкнулся с некоторыми проблемами, такими как RemoteServiceException, из-за недопустимого идентификатора канала в самых последних версиях Android. Вот как я это решил:

Действия:

override fun onCreate(savedInstanceState: Bundle?) {
    val intent = Intent(this, BackgroundService::class.java)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(intent)
    } else {
        startService(intent)
    }
}

BackgroundService:

override fun onCreate() {
    super.onCreate()
    startForeground()
}

private fun startForeground() {

    val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    val channelId =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                createNotificationChannel()
            } else {
                // If earlier version channel ID is not used
                // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
                ""
            }

    val notificationBuilder = NotificationCompat.Builder(this, channelId )
    val notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setPriority(PRIORITY_MIN)
            .setCategory(Notification.CATEGORY_SERVICE)
            .build()
    startForeground(101, notification)
}


@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(): String{
    val channelId = "my_service"
    val channelName = "My Background Service"
    val chan = NotificationChannel(channelId,
            channelName, NotificationManager.IMPORTANCE_HIGH)
    chan.lightColor = Color.BLUE
    chan.importance = NotificationManager.IMPORTANCE_NONE
    chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
    val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    service.createNotificationChannel(chan)
    return channelId
}

ЭКВИВАЛЕНТ JAVA

public class YourService extends Service {

    // Constants
    private static final int ID_SERVICE = 101;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // do stuff like register for BroadcastReceiver, etc.

        // Create the Foreground Service
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? createNotificationChannel(notificationManager) : "";
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
        Notification notification = notificationBuilder.setOngoing(true)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setPriority(PRIORITY_MIN)
                .setCategory(NotificationCompat.CATEGORY_SERVICE)
                .build();

        startForeground(ID_SERVICE, notification);
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private String createNotificationChannel(NotificationManager notificationManager){
        String channelId = "my_service_channelid";
        String channelName = "My Foreground Service";
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
        // omitted the LED color
        channel.setImportance(NotificationManager.IMPORTANCE_NONE);
        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        notificationManager.createNotificationChannel(channel);
        return channelId;
    }
}
person Rawa    schedule 29.11.2017
comment
Вы можете использовать ContextCompat.startForegroundService(Context,Intent) в своей деятельности, которая будет делать правильные вещи. (developer.android.com/reference/android/support/v4 / content /) - person Simon Featherstone; 22.02.2018
comment
вы, вероятно, захотите использовать .setCategory(NotificationCompat.CATEGORY_SERVICE) вместо Notification.CATEGORY_SERVICE, если ваш min API равен ‹21 - person Someone Somewhere; 26.06.2018
comment
Обратите внимание, что приложения, ориентированные на Build.VERSION_CODES.P (уровень API 28) или более поздние, должны запрашивать разрешение Manifest.permission.FOREGROUND_SERVICE, чтобы использовать startForeground() - см. developer.android.com/reference/android/app/ - person Vadim Kotov; 11.01.2019

Это мой код для установки службы на передний план:

private void runAsForeground(){
    Intent notificationIntent = new Intent(this, RecorderMainActivity.class);
    PendingIntent pendingIntent=PendingIntent.getActivity(this, 0,
            notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

    Notification notification=new NotificationCompat.Builder(this)
                                .setSmallIcon(R.drawable.ic_launcher)
                                .setContentText(getString(R.string.isRecording))
                                .setContentIntent(pendingIntent).build();

    startForeground(NOTIFICATION_ID, notification);

}

Мне нужно создать уведомление с помощью PendingIntent, чтобы я мог начать свое основное действие из уведомления.

Чтобы удалить уведомление, просто вызовите stopForeground (true);

Он вызывается в onStartCommand (). См. Мой код по адресу: https://github.com/bearstand/greyparrot/blob/master/src/com/xiong/richard/greyparrot/Mp3Recorder.java

person Richard    schedule 26.01.2015
comment
Если вы удалите уведомление, вызывающее stopForeground (true), вы отменяете службу startforeground - person sdelvalle57; 30.09.2015
comment
Откуда вы вызываете этот метод? - person Srujan Barai; 23.11.2015
comment
Intent.FLAG_ACTIVITY_NEW_TASK недействителен в контексте PendingIntent. - person mixel; 22.12.2015

В дополнение к ответу RAWA, этот кусок кода:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    startForegroundService(intent)
} else {
    startService(intent)
}

Вы можете изменить на:

ContextCompat.startForegroundService(context, yourIntent);

Если вы заглянете внутрь этого метода, то увидите, что он выполняет всю работу по проверке за вас.

person Edgar Khimich    schedule 25.08.2018

Если вы хотите сделать IntentService службой переднего плана

тогда вы должны переопределить onHandleIntent() как это

Override
protected void onHandleIntent(@Nullable Intent intent) {


    startForeground(FOREGROUND_ID,getNotification());     //<-- Makes Foreground

   // Do something

    stopForeground(true);                                // <-- Makes it again a normal Service                         

}

Как сделать уведомление?

просто. Вот метод getNotification()

public Notification getNotification()
{

    Intent intent = new Intent(this, SecondActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,0);


    NotificationCompat.Builder foregroundNotification = new NotificationCompat.Builder(this);
    foregroundNotification.setOngoing(true);

    foregroundNotification.setContentTitle("MY Foreground Notification")
            .setContentText("This is the first foreground notification Peace")
            .setSmallIcon(android.R.drawable.ic_btn_speak_now)
            .setContentIntent(pendingIntent);


    return foregroundNotification.build();
}

Более глубокое понимание

Что происходит, когда сервис становится сервисом переднего плана

Это случилось

введите описание изображения здесь

Что такое служба переднего плана?

Служба переднего плана,

  • гарантирует, что пользователь активно осведомлен о том, что что-то происходит в фоновом режиме, предоставляя уведомление.

  • (самое главное) не убивается системой, когда ей не хватает памяти

Пример использования службы переднего плана

Реализация функции загрузки песен в музыкальном приложении

person Rohit Singh    schedule 03.11.2017

Добавить указанный класс обслуживания кода для "OS> = Build.VERSION_CODES.O" в onCreate ()

@Override
public void onCreate(){
    super.onCreate();

     .................................
     .................................

    //For creating the Foreground Service
    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? getNotificationChannel(notificationManager) : "";
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
    Notification notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.mipmap.ic_launcher)
           // .setPriority(PRIORITY_MIN)
            .setCategory(NotificationCompat.CATEGORY_SERVICE)
            .build();

    startForeground(110, notification);
}



@RequiresApi(Build.VERSION_CODES.O)
private String getNotificationChannel(NotificationManager notificationManager){
    String channelId = "channelid";
    String channelName = getResources().getString(R.string.app_name);
    NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
    channel.setImportance(NotificationManager.IMPORTANCE_NONE);
    channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
    notificationManager.createNotificationChannel(channel);
    return channelId;
}

Добавьте это разрешение в файл манифеста:

 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
person Kush    schedule 02.12.2018

Обработайте намерение startCommand службы с помощью.

 stopForeground(true)

Этот вызов удаляет службу из состояния переднего плана, позволяя убить ее, если потребуется больше памяти. Это не останавливает работу службы. Для этого вам нужно вызвать stopSelf () или связанные с ним методы.

Передаваемое значение true или false указывает, хотите ли вы удалить уведомление или нет.

val ACTION_STOP_SERVICE = "stop_service"
val NOTIFICATION_ID_SERVICE = 1
...  
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
    super.onStartCommand(intent, flags, startId)
    if (ACTION_STOP_SERVICE == intent.action) {
        stopForeground(true)
        stopSelf()
    } else {
        //Start your task

        //Send forground notification that a service will run in background.
        sendServiceNotification(this)
    }
    return Service.START_NOT_STICKY
}

Выполняйте свою задачу, когда при уничтожении вызывается stopSelf ().

override fun onDestroy() {
    super.onDestroy()
    //Stop whatever you started
}

Создайте уведомление, чтобы служба продолжала работать на переднем плане.

//This is from Util class so as not to cloud your service
fun sendServiceNotification(myService: Service) {
    val notificationTitle = "Service running"
    val notificationContent = "<My app> is using <service name> "
    val actionButtonText = "Stop"
    //Check android version and create channel for Android O and above
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        //You can do this on your own
        //createNotificationChannel(CHANNEL_ID_SERVICE)
    }
    //Build notification
    val notificationBuilder = NotificationCompat.Builder(applicationContext, CHANNEL_ID_SERVICE)
    notificationBuilder.setAutoCancel(true)
            .setDefaults(NotificationCompat.DEFAULT_ALL)
            .setWhen(System.currentTimeMillis())
            .setSmallIcon(R.drawable.ic_location)
            .setContentTitle(notificationTitle)
            .setContentText(notificationContent)
            .setVibrate(null)
    //Add stop button on notification
    val pStopSelf = createStopButtonIntent(myService)
    notificationBuilder.addAction(R.drawable.ic_location, actionButtonText, pStopSelf)
    //Build notification
    val notificationManagerCompact = NotificationManagerCompat.from(applicationContext)
    notificationManagerCompact.notify(NOTIFICATION_ID_SERVICE, notificationBuilder.build())
    val notification = notificationBuilder.build()
    //Start notification in foreground to let user know which service is running.
    myService.startForeground(NOTIFICATION_ID_SERVICE, notification)
    //Send notification
    notificationManagerCompact.notify(NOTIFICATION_ID_SERVICE, notification)
}

Дайте кнопку остановки при уведомлении, чтобы остановить службу, когда это необходимо пользователю.

/**
 * Function to create stop button intent to stop the service.
 */
private fun createStopButtonIntent(myService: Service): PendingIntent? {
    val stopSelf = Intent(applicationContext, MyService::class.java)
    stopSelf.action = ACTION_STOP_SERVICE
    return PendingIntent.getService(myService, 0,
            stopSelf, PendingIntent.FLAG_CANCEL_CURRENT)
}
person Rana Ranvijay Singh    schedule 03.10.2018

Примечание. Если ваше приложение нацелено на уровень API 26 или выше, система накладывает ограничения на использование или создание фоновых служб, если само приложение не находится на переднем плане.

Если приложению необходимо создать службу переднего плана, оно должно вызвать startForegroundService(). Этот метод создает фоновую службу, но метод сигнализирует системе, что служба будет продвигать себя на передний план.

После создания службы она должна вызвать ее startForeground() method within five seconds.

person Andrii Kovalchuk    schedule 03.01.2019
comment
Надеюсь, вы говорите о текущем вопросе. В противном случае в сообществе Stackoverflow такого правила нет. - person Farid; 07.09.2019
comment
@RogerGusmao в готовом для производства коде среды не всегда спасет ваш проект. К тому же - есть много отличных примеров с кодом ниже и выше моего ответа .. У моего проекта были проблемы во время выпуска именно потому, что я не знал о методе startForegroundService - person Andrii Kovalchuk; 09.12.2019

В моем случае все было по-другому, так как у меня не было активности по запуску сервиса в Oreo.

Ниже приведены шаги, которые я использовал для решения этой проблемы службы переднего плана:

public class SocketService extends Service {
    private String TAG = this.getClass().getSimpleName();

    @Override
    public void onCreate() {
        Log.d(TAG, "Inside onCreate() API");
        if (Build.VERSION.SDK_INT >= 26) {
            NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
            mBuilder.setSmallIcon(R.drawable.ic_launcher);
            mBuilder.setContentTitle("Notification Alert, Click Me!");
            mBuilder.setContentText("Hi, This is Android Notification Detail!");
            NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            // notificationID allows you to update the notification later on.
            mNotificationManager.notify(100, mBuilder.build());
            startForeground(100, mBuilder.mNotification);
        }
        Toast.makeText(getApplicationContext(), "inside onCreate()", Toast.LENGTH_LONG).show();
    }


    @Override
    public int onStartCommand(Intent resultIntent, int resultCode, int startId) {
        Log.d(TAG, "inside onStartCommand() API");

        return startId;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "inside onDestroy() API");

    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }
}

И после этого, чтобы запустить эту службу, я запустил ниже cmd -


adb -s "+ serial_id +" оболочка am startforegroundservice -n com.test.socket.sample / .SocketService


Так что это помогает мне запускать сервис без активности на устройствах Oreo :)

person Arpana    schedule 26.02.2018

Решение @mikebertiean почти помогло, но у меня возникла проблема с дополнительным поворотом - я использую систему Gingerbread, и я не хотел добавлять дополнительный пакет только для запуска уведомления. Наконец, я обнаружил: https://android.googlesource.com/platform/frameworks/support.git+/f9fd97499795cd47473f0344e00db9c9837eea36/v4/gingerbread/android/support/v4/app/NotificationCompatolofread.ua/

тогда я столкнулся с дополнительной проблемой - уведомление просто убивает мое приложение при запуске (как решить эту проблему: Android: как избежать того, что нажатие на уведомление вызывает onCreate ()), поэтому в целом мой служебный код выглядит следующим образом (C # / Xamarin):

Intent notificationIntent = new Intent(this, typeof(MainActivity));
// make the changes to manifest as well
notificationIntent.SetFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop);
PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification(Resource.Drawable.Icon, "Starting service");
notification.SetLatestEventInfo(this, "MyApp", "Monitoring...", pendingIntent);
StartForeground(1337, notification);
person greenoldman    schedule 29.06.2020