72

I am trying to stop a service which is running as foreground service.

The current issue is that when I call stopService() the notification still stays.

So in my solution I have added a receiver which I am registering to inside the onCreate()

Inside the onReceive() method I call stopforeground(true) and it hides the notification. And then stopself() to stop the service.

Inside the onDestroy() I unregistered the receiver.

Is there a more proper way to handle this? because stopService() simply doesn't work.

@Override
public void onDestroy(){
  unregisterReceiver(receiver);
  super.onDestroy();
}
Mercury
  • 7,430
  • 3
  • 42
  • 54
user1940676
  • 4,348
  • 9
  • 44
  • 73

8 Answers8

101
  1. From your activity, call startService(intent) and pass it some data representing a key to stop the service.
  2. From your service, call stopForeground(true)
  3. and then stopSelf() right after it.
Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216
  • 4
    inside the onDestroy()? – user1940676 Dec 31 '13 at 12:24
  • 1
    @user1940676, no, just from the point where you wish to stop it and remove the notification – Ilya Gazman Dec 31 '13 at 12:25
  • stopforeground is a service method, I don't think if I can or should call it from an activity. – user1940676 Dec 31 '13 at 12:28
  • 1
    @user1940676 You need to call it from the service it self. You need some how to tell him that he need to finish him self. You can pass data on intent, it will be received Service.onStart() – Ilya Gazman Dec 31 '13 at 12:33
  • yea that is what I was thinking, just call startservice() with an extra. – user1940676 Dec 31 '13 at 12:33
  • This does not work for me. I can't understand why :( – Vedant Agarwala Dec 03 '15 at 15:06
  • Do you have any idea on how to start a service from Broadcast receiver in Android Oreo? – Rahulrr2602 Dec 24 '18 at 09:43
  • The downside to stopping a Foreground Service in `startService(...)` with intent data is that you'll need to check if the Foreground Service is running which requires deprecated code not meant for production - [How to determine if an Android Service is running in the foreground?](https://stackoverflow.com/questions/6452466/how-to-determine-if-an-android-service-is-running-in-the-foreground/56499477#56499477) – AdamHurwitz Jun 07 '19 at 19:11
  • 1
    is there a specific benefit to the order of calls? Is it important to do `stopForeground` first, before `stopSelf`? – avalancha Aug 28 '19 at 11:51
  • This does not seem to work for IntentService started by context.startForegroundService() from a BroadcastReceiver. The notification still shows the associated app is running. – Hong Jan 23 '20 at 20:04
  • 3
    Is it mandatory to call stopForeground() ?? only calling stopSelf() is not sufficient ?? In my case, i'm just calling stopSelf() and it is working, notification is being removed. – K Pradeep Kumar Reddy May 14 '20 at 11:23
  • its not working for `MediaLibraryService`. look at this [question](https://stackoverflow.com/questions/76231883/how-to-stop-medialibraryservicemedia3-android/76231966#76231966) – Ebrahim Karimi May 12 '23 at 08:17
66

to start and stop a foreground service from an activity use :

//start
    Intent startIntent = new Intent(MainActivity.this, ForegroundService.class);
    startIntent.setAction(Constants.ACTION.STARTFOREGROUND_ACTION);
    startService(startIntent);
//stop
    Intent stopIntent = new Intent(MainActivity.this, ForegroundService.class);
    stopIntent.setAction(Constants.ACTION.STOPFOREGROUND_ACTION);
    startService(stopIntent);

in your foreground service - use (at least) this code:

@Override
 public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
        Log.i(LOG_TAG, "Received Start Foreground Intent ");
        // your start service code
    }
    else if (intent.getAction().equals( Constants.ACTION.STOPFOREGROUND_ACTION)) {
        Log.i(LOG_TAG, "Received Stop Foreground Intent");
    //your end servce code
        stopForeground(true);
        stopSelfResult(startId);
    }
    return START_STICKY;
}
Ali Maddi
  • 309
  • 3
  • 8
Elad
  • 1,523
  • 13
  • 10
15

As stated here: https://developer.android.com/guide/components/services#Stopping

A started service must manage its own lifecycle. That is, the system doesn't stop or destroy the service unless it must recover system memory and the service continues to run after onStartCommand() returns. The service must stop itself by calling stopSelf(), or another component can stop it by calling stopService().

Once requested to stop with stopSelf() or stopService(), the system destroys the service as soon as possible.

So you can call stopService() from the activity that you used to call startService(). I have done that right here:

start_button.setOnClickListener {
            applicationContext.startForegroundService(Intent(this, ServiceTest::class.java))
        }
stop_button.setOnClickListener {
            applicationContext.stopService(Intent(this, ServiceTest::class.java))
        }

I created two buttons to start and stop the service and it works.

Ahmed Shahid
  • 300
  • 3
  • 9
13

From Activity

 stopService(new Intent(this, ForegroundService.class));

From Service itself

  stopForeground(true);
  stopSelf()
beginner
  • 2,366
  • 4
  • 29
  • 53
3

In addition to other answers i ended with this snippet using android oreo and laters to stop job services.

Intent intent = new Intent(getApplicationContext(), LocationService.class);
intent.setAction(status);
ContextCompat.startForegroundService(getApplicationContext(), intent);

And in service

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
  startForeground(121, notification);
  if (intent.getAction().equals("StopService")) {
    stopForeground(true);
    stopSelf();
  }

startForeground() is mandatory unless app will crash without calling it

The new Context.startForegroundService() method starts a foreground service. The system allows apps to call Context.startForegroundService() even while the app is in the background. However, the app must call that service's startForeground() method within five seconds after the service is created.

https://developer.android.com/about/versions/oreo/android-8.0-changes.html

Nerius Jok
  • 3,059
  • 6
  • 21
  • 27
0

If you want to stop service and then update notification, you can first call stopSelf() and then notify(). stopForeground(false) makes the notification cancelable.

 private final BroadcastReceiver myBgWorkCompleteReceiver= new BroadcastReceiver() {
        @Override
  public void onReceive(Context context, Intent intent) {
            stopSelf();
            notificationLayoutExpanded.setTextViewText(R.id.file_download_notify_download_percentage, "Background work completed");
            manager.notify(mNotificationId, notification);
            stopForeground(false);
        }
};


 public void onDestroy() {
        super.onDestroy();
        // cancel any running threads here
        LocalBroadcastManager.getInstance(this).unregisterReceiver(myBgWorkCompleteReceiver);
    }
LincyTonita
  • 327
  • 4
  • 14
0

I have found the best way to stop a service is to make stop itself. This way you are sure it actually will stop and preserve data integrity. If you want to do it from outside (activity) I usually use a global static attribute.

Check my answer here : https://stackoverflow.com/a/57833370/7795547

D Dimitrov
  • 115
  • 1
  • 10
0
  • You can stop service from service or activity

From service:

 stopForeground(true);
 stopSelf();

From activity:

stopService(new Intent(this, MyService.class));
//MyService is your service