144

So I'm not sure where/how to implement this method to make my service run in the foreground. Currently I start my service by the following in another activity:

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

And then in myServices' onCreate() I try the startForeground()...?

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

So yeah I'm a bit lost and unsure of how to implement this.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
JDS
  • 16,388
  • 47
  • 161
  • 224
  • Well this doesn't work, at least as far as I can tell my service still works as a background service and gets killed. – JDS Jun 18 '11 at 18:06
  • Thread is linked to : http://stackoverflow.com/questions/10962418/startforeground-without-showing-notification/12851219#12851219 – Snicolas Oct 12 '12 at 15:07

11 Answers11

141

I'd start by completely filling in the Notification. Here is a sample project demonstrating the use of startForeground().

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 10
    Is it possible to use startForeground() without notification? Or can we later update same notification? – JRC Jan 09 '12 at 06:05
  • 4
    Is there a particular reason you used `1337`? – Cody Feb 17 '12 at 17:25
  • 37
    @DoctorOreo: It needs to be unique within the app, though not necessarily unique on the device. I chose 1337 because, well, it is [1337](http://en.wikipedia.org/wiki/Leet). :-) – CommonsWare Feb 17 '12 at 17:40
  • @JRC question is a good one. Is it possible to use startForeground() without notification? – Snicolas Oct 12 '12 at 01:51
  • 2
    @Snicolas: Thank you for pointing out a flaw in Android. I will work on getting this fixed. – CommonsWare Oct 12 '12 at 15:19
  • Actually, it may be an interesting mechanism. Of course this can lead to a very bad practice of putting services in the foreground without notifying the user, but it can also be handy. By this I mean that it's very difficult to manage a service in android that is both started and bound by different activities. If the service can't access to foreground, it is killed and recreated after every unbinding operation. This is not documented (I believe) and just makes it impossible to have some stable service used by binding. A nice fix would be allow this or not through a permission. – Snicolas Oct 12 '12 at 17:19
  • @Snicolas: "If the service can't access to foreground, it is killed and recreated after every unbinding operation." -- I am not aware that foreground has any impact on this. If this indeed is the case, that too may represent a bug. – CommonsWare Oct 12 '12 at 17:29
  • @CommonsWare, I was saying to myself that I was maybe requesting a feature for a bug workaround. But if silent forground service are prohibited, then I would really love that the same release clearly provides a way to get a service that support a mixed life cycle (bound and started). This service feature is essential to my mind and I tend to believe that many people are expecting this too.`` – Snicolas Oct 12 '12 at 17:44
  • @Snicolas: "a service that support a mixed life cycle (bound and started)" -- while I have never done it, it would appear that lots of other developers have no issue using both `startService()` and `bindService()`. – CommonsWare Oct 12 '12 at 17:46
  • I saw some threads on it on SOF. But another question ? How can a service survive my app if not on set on foreground ? I mean survive when I kill the app using the task switcher. Oh, and with the service in the same process as the app. – Snicolas Oct 13 '12 at 00:17
  • @Snicolas: No service "survives" being killed by a task killer, regardless of whether or not your service is in the foreground or not. – CommonsWare Oct 13 '12 at 10:41
  • @CommonsWare Not the task killer, but the user friendly task switcher provided by a long click on the home button (above HoneyComb I believe, but maybe ICS). – Snicolas Oct 14 '12 at 09:17
  • @Snicolas: Your service will not be immediately affected by another app's activities coming to the foreground, by any means. – CommonsWare Oct 14 '12 at 10:38
  • @CommonsWare I am glad we are having this talk, but we are actually out of topic. Is there any mean by wich I could contact you directly ? I was not meaning swtiching to a new task could affect my app, I was talking about using the task switcher to kill the app (sliding it right), which is a more user friendly way to kill app than using the applications menu in the settings app of the Android phone (although both way don't have the same impact). – Snicolas Oct 14 '12 at 16:30
  • @CommonsWare I realize this is an old discussion, but in the project that's pointed to by the link above, `FakePlayer`, neither `FakePlayer.java` nor `PlayerService.java` has a method called `startForeground()`. Am I missing something? I'm very new to services and am trying to learn by playing around with bits and pieces of code. Thank you. – aLearner Dec 29 '12 at 12:19
  • @CommonsWare To add to what I wrote, I also noticed that the service starts off fine but if I open many (resource-heavy) apps and then hit the home button (so, not destroying them), I see the following three lines in the LogCat after which the service seems to die (since I don't see it under `Menu --> Manage apps --> Running` - as it did previously). Note that the time and date have been stripped for brevity. `[1] D/ActivityThread(3487): setTargetHeapUtilization:0.25 [2] D/ActivityThread(3487): setTargetHeapIdealFree:8388608 [3] D/ActivityThread(3487): setTargetHeapConcurrentStart:2097152` – aLearner Dec 29 '12 at 12:48
  • @aLearner: `PlayerService` calls `startForeground()`, line 70. And I have no idea what those log messages mean. – CommonsWare Dec 29 '12 at 13:29
  • @CommonsWare: Thank you. I don't see line 70. The `PlayerService.java` file I'm looking at has only 62 lines. Thanks again. – aLearner Dec 29 '12 at 18:21
  • @aLearner: https://github.com/commonsguy/cw-android/blob/master/Notifications/FakePlayer/src/com/commonsware/android/fakeplayerfg/PlayerService.java has 81 lines. – CommonsWare Dec 29 '12 at 18:39
  • @CommonsWare Right. Thank you very much. Don't know how I ended up with a 62-line `PlayerService.java` file. Both times I went to: https://github.com/commonsguy/cw-android and clicked on `ZIP`. I found the project under `Notifications --> FakePlayer\ --> src --> com --> commonsware --> android --> fakeplayerfg (fakeplayer)`. Anyway, I downloaded everything again and I do indeed see 81 lines now. The `PlayerService.java` file I have has a date stamp of Feb 13, 2012 and the newer one I downloaded has a date stamp of Dec 30, 2012 - so perhaps there was an update. Thanks again for all your help. – aLearner Dec 30 '12 at 04:57
  • @CommonsWare I finally figured it out. The links you shared point to `.../Notifications/FakePlayer`. However, there also exists another project with the same name at `.../Service/FakePlayer`. This is what tripped me up - especially since I downloaded all the projects as a `ZIP` file and then navigated to the `Service` folder instead of the `Notifications` folder. Phew! – aLearner Jan 01 '13 at 05:25
  • @CommonsWare, more than one year after, the vulnerability of displaying a 0 iconed notification has been patched in JB. It's pretty aweseome the way it's been done btw. Thanks Mark, in RoboSpice we are actually finalizing a new implementation of our services that will make our services super clean with this respect : our services will go in foreground only when they are not bound and have some thing to do, and in that case only the will display a foreground notification. Did you contribute to that vulnerability being patched ? – Snicolas Aug 16 '13 at 22:47
  • @Snicolas: "that will make our services super clean with this respect : our services will go in foreground only when they are not bound and have some thing to do, and in that case only the will display a foreground notification" -- that would be singularly wonderful. "Did you contribute to that vulnerability being patched ?" -- I filed an issue on it. Since the issue was never accepted, I would assume that it had no impact. – CommonsWare Aug 16 '13 at 22:50
  • @CommonsWare . Hummm, I prefer to believe you did help to it. And maybe did I in a minor measure. We need some personal myth, don't we ? :) Well, before we meet again at DroidCon London / Anddev, would you have some time to try RoboSpice ? :) – Snicolas Aug 16 '13 at 22:53
  • @Snicolas: Someday, perhaps, but I have a *long* to-do list. – CommonsWare Aug 16 '13 at 22:59
  • Implementation of `Notification` is deprecated. I'd go with the other high rated answer. – OneWorld Mar 22 '17 at 15:45
  • @OneWorld: The only other answers on this question are demonstrating what I refer to in my answer. – CommonsWare Mar 22 '17 at 16:03
  • This is a very old thread, but I'd like to ask if making a service into a foreground service is equally applicable for a Service as for an IntentService (which your sample project is based on). – RenniePet Apr 29 '17 at 08:52
  • @RenniePet: If anything, it is *more* applicable to a regular `Service`. It really depends on what the service is doing. – CommonsWare Apr 29 '17 at 11:19
  • @CommonsWare Looking at the sample on Github, shouldn't we use the new startForegroundService of Android O ? – android developer Jan 15 '18 at 23:12
  • @androiddeveloper: That is not necessary, as the service is being started from the foreground. `startBackgroundService()` is needed if your code is already in the background for one reason or another and needs to start a service. That being said, you're welcome to use it from the foreground as well. – CommonsWare Jan 15 '18 at 23:18
  • @CommonsWare Why the need of this differentiation, if it can accomplish the same thing as before Android O ? Also, it's `startForegroundService` ... – android developer Jan 16 '18 at 07:44
  • @androiddeveloper: Because sometimes your app is already in the background when you need to start a foreground service, such as having received a broadcast. Also, sorry about the typo. – CommonsWare Jan 16 '18 at 11:37
  • @CommonsWare I don't understand. So what if it's in the background? It's still possible to start the service in the foreground even on this case. What does it accomplish to differentiate this way? – android developer Jan 16 '18 at 11:43
  • @androiddeveloper: "It's still possible to start the service in the foreground even on this case" -- no, you cannot. See [the documentation](https://developer.android.com/about/versions/oreo/background.html#services). – CommonsWare Jan 16 '18 at 11:47
  • @CommonsWare I don't understand. Suppose I create an app that, like an Alarm clock app, gets opened on a specific time (or a different, global trigger), I can't create a foreground service before showing an Activity ? – android developer Jan 16 '18 at 12:17
  • @androiddeveloper: You can, via `startForegroundService()` on `Context` or `getForegroundService()` on `PendingIntent`. – CommonsWare Jan 16 '18 at 12:25
  • @CommonsWare So as I wrote, it's still possible, just as before, to create a foreground service in all cases, whether your app is in the background or in the foreground, no? – android developer Jan 16 '18 at 12:31
  • @androiddeveloper: It is possible, if you choose the proper method to do so, as I wrote. – CommonsWare Jan 16 '18 at 12:42
  • @CommonsWare This was the question: Why the need of this extra function, if we could have done the same thing before... I think that they did it only because they allow just foreground services to be opened when the app is in the background: " With Android 8.0, there is a complication; the system doesn't allow a background app to create a background service. For this reason, Android 8.0 introduces the new method startForegroundService() to start a new service in the foreground. " . Just to remind us that the new service must be a foreground service pretty soon, if we wish to let it stay longer – android developer Jan 16 '18 at 13:59
  • @androiddeveloper: IMHO, it goes beyond "just to remind us". If you try calling `startService()` from the background, it fails on Android 8.0+. Nothing about this change enables new functionality. It merely provides options for maintaining existing functionality, where that functionality happens to fit within the guidelines. – CommonsWare Jan 16 '18 at 14:03
  • @CommonsWare It fails because they want a foreground service. I wonder though what would happen if you use `startForegroundService` without making it a real foreground service soon afterwards. Would it crash, or do something else? And, does it mean that a background service can be used in this small time window? – android developer Jan 16 '18 at 14:13
  • @androiddeveloper: "Would it crash, or do something else?" -- yes, after the ANR period. "And, does it mean that a background service can be used in this small time window?" -- if you don't mind crashing, yes. You crash even if you stop the service, if you did not call `startForeground()`. This is *seriously* aggravating. – CommonsWare Jan 16 '18 at 14:22
  • @CommonsWare Not sure I understand. You mean it will crash no matter what I do, if I don't call `startForeground` ? For example, if I start a new thread there, that does a very short job (say, of 2 seconds), and then I choose to stop the service, it will still crash? – android developer Jan 16 '18 at 14:40
  • @androiddeveloper: Yes on both counts. – CommonsWare Jan 16 '18 at 15:00
  • @CommonsWare Interesting. Is an app considered background in the next case (I want to check it out) : "user sees an Activity of the app, and presses the home key (seeing the launcher now instead) " ? – android developer Jan 16 '18 at 15:45
  • @androiddeveloper: Yes, after a minute's grace period. If you have further concerns in this area, please ask a separate Stack Overflow question, rather than continuing to chain more and more comments on this unrelated answer. – CommonsWare Jan 16 '18 at 15:48
  • @CommonsWare I am trying to make a service that only the user can start or stop. Right now I start foreground from onstartcommand but when I close the app the service stops after about 15-20 minutes and the notification dissapears. Do you have anything on GitHub where only user can start or stop service? – JRowan Mar 26 '19 at 19:43
  • Here is the service I'm talking about if you'd like to take a look https://github.com/copypasteearth/Powerball-MegaMillions/blob/master/app/src/main/java/powerball/apps/jacs/powerball/PowerballSimulatorService.java – JRowan Mar 26 '19 at 19:46
  • @JRowan: "I am trying to make a service that only the user can start or stop" -- sorry, but I do not know what you mean by that. You might consider asking a separate Stack Overflow question where you can explain your concerns in greater detail. – CommonsWare Mar 26 '19 at 23:14
  • foreground service with out notification how to show – Harsha Apr 28 '20 at 12:09
  • @Harsha: Sorry, but that is not available. – CommonsWare Apr 28 '20 at 12:17
86

From your main activity, start the service with the following code:

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

Then in your service for onCreate() you would build your notification and set it as foreground like so:

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);
mikebertiean
  • 3,611
  • 4
  • 20
  • 29
  • @mike how to update this notification from MainActivity? – Roon13 Sep 15 '17 at 15:25
  • 1
    @Roon13 using the ID, in this case 1337 ... you should be able to build a new notification and call startForeground with the ID – mikebertiean Sep 15 '17 at 15:35
  • @Roon13 check out this question https://stackoverflow.com/questions/5528288/how-do-i-update-the-notification-text-for-a-foreground-service-in-android – mikebertiean Sep 15 '17 at 15:35
  • @mikebertiean How can I call the startForeground from MainActivity? also how can i clear the notfication from MainActvity when process is finished? – Roon13 Sep 15 '17 at 16:23
  • @mikebertiean I got that i have to call startForeground again in Service class but how? Do I have to call startService() again? – Roon13 Sep 15 '17 at 16:31
  • @mikebertiean never mind I used notificationmanager to update notification from MainActivity. It worked. – Roon13 Sep 15 '17 at 17:47
  • NotificationCompat.builder(context) is deprecated. You now need to include changel id - NotificationCompat.builder(context, channelId). – A.J. Feb 23 '18 at 03:15
  • 2
    Don't forget: – Reeman Adel Mar 22 '20 at 17:51
47

Solution for Oreo 8.1

I've encountered some problems such as RemoteServiceException because of invalid channel id with most recent versions of Android. This is how i solved it:

Activity:

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 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 EQUIVALENT

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;
    }
}
Shubham Gupta
  • 1,123
  • 11
  • 16
Rawa
  • 13,357
  • 6
  • 39
  • 55
  • 8
    You can use `ContextCompat.startForegroundService(Context,Intent)` in your Activity which will do the right thing. (https://developer.android.com/reference/android/support/v4/content/ContextCompat.html) – Simon Featherstone Feb 22 '18 at 17:54
  • 3
    you'll probably want to use `.setCategory(NotificationCompat.CATEGORY_SERVICE)` instead of `Notification.CATEGORY_SERVICE` if your min API is < 21 – Someone Somewhere Jun 26 '18 at 14:20
  • 9
    Please note that apps targeting `Build.VERSION_CODES.P` (API level 28) or later must request the permission `Manifest.permission.FOREGROUND_SERVICE` in order to use `startForeground()` - see https://developer.android.com/reference/android/app/Service.html#startForeground(int,%20android.app.Notification) – Vadim Kotov Jan 11 '19 at 12:55
  • the permission step by step please.... if anything different from the usual one. :D @VadimKotov – gumuruh Apr 26 '22 at 03:48
  • in android 12 startforgroundservice() causes ForegroundServiceStartNotAllowedException . do anyone know a solution ? – Liya Nov 30 '22 at 09:49
32

This is my code to set the service to foreground:

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);

}

I need to build a notification using PendingIntent, so that I can start my main activity from the notification.

To remove the notification, just call the stopForeground(true);

It is called in the onStartCommand(). Please refer to my code at : https://github.com/bearstand/greyparrot/blob/master/src/com/xiong/richard/greyparrot/Mp3Recorder.java

Richard
  • 546
  • 4
  • 6
23

In addition to RAWA answer, this peace of code:

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

You can change to:

ContextCompat.startForegroundService(context, yourIntent);

If you will look inside this method then you can see that this method do all checking work for you.

Edhar Khimich
  • 1,468
  • 1
  • 17
  • 20
15

If you want to make IntentService a Foreground Service

then you should override onHandleIntent()like this

Override
protected void onHandleIntent(@Nullable Intent intent) {


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

   // Do something

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

}

   

How to make notification ?

simple. Here is the getNotification() Method

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();
}

Deeper Understanding

What happens when a service becomes a foreground service

This happens

enter image description here

What is a foreground Service ?

A foreground service,

  • makes sure that user is actively aware of that something is going on in the background by providing the notification.

  • (most importantly) is not killed by System when it runs low on memory

A use case of foreground service

Implementing song download functionality in a Music App

CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
Rohit Singh
  • 16,950
  • 7
  • 90
  • 88
9

Add given code Service class for "OS >= Build.VERSION_CODES.O" in 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;
}

Add this permission in manifest file:

 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Kush
  • 1,080
  • 11
  • 15
3

Handle intent on startCommand of service by using.

 stopForeground(true)

This call will remove the service from foreground state, allowing it to be killed if more memory is needed. This does not stop the service from running. For that, you need to call stopSelf() or related methods.

Passing value true or false indicated if you want to remove the notification or not.

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
}

Handle your task when on destroy is called by stopSelf().

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

Create a notification to keep the service running in foreground.

//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)
}

Give a stop button on notification to stop the service when user needs.

/**
 * 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)
}
Rana Ranvijay Singh
  • 6,055
  • 3
  • 38
  • 54
1

Note: If your app targets API level 26 or higher, the system imposes restrictions on using or creating background services unless the app itself is in the foreground.

If an app needs to create a foreground service, the app should call startForegroundService(). That method creates a background service, but the method signals to the system that the service will promote itself to the foreground.

Once the service has been created, the service must call its startForeground() method within five seconds.

Andrii Kovalchuk
  • 4,351
  • 2
  • 36
  • 31
  • 1
    I hope you're talking about the current question. Otherwise, there is no such rule in Stackoverflow community – Farid Sep 07 '19 at 08:49
  • @RogerGusmao in production-ready environment code will not always save your project. Besides - there are lot of great examples with code below and above my answer.. My project had issues during the release exactly because I didn't know about `startForegroundService` method – Andrii Kovalchuk Dec 09 '19 at 18:40
0

In my case It was totally different since I was not having activity to launch the service in Oreo.

Below are the steps which I used to resolve this foreground service issue -

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;
    }
}

And after that to initiate this service I triggered below cmd -


adb -s " + serial_id + " shell am startforegroundservice -n com.test.socket.sample/.SocketService


So this helps me to start service without activity on Oreo devices :)

Spettacolo83
  • 282
  • 4
  • 10
Arpana
  • 342
  • 1
  • 3
  • 13
0

@mikebertiean solution almost did the trick, but I had this problem with additional twist -- I use Gingerbread system and I didn't want to add some extra package just to run notification. Finally I found: https://android.googlesource.com/platform/frameworks/support.git+/f9fd97499795cd47473f0344e00db9c9837eea36/v4/gingerbread/android/support/v4/app/NotificationCompatGingerbread.java

then I hit additional problem -- notification simply kills my app when it runs (how to solve this problem: Android: How to avoid that clicking on a Notification calls onCreate()), so in total my code in service looks like this (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);
greenoldman
  • 16,895
  • 26
  • 119
  • 185