相关文章推荐
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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.

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, 2011 at 18:06 Is it possible to use startForeground() without notification? Or can we later update same notification? – JRC Jan 9, 2012 at 6:05 @DoctorOreo: It needs to be unique within the app, though not necessarily unique on the device. I chose 1337 because, well, it is 1337. :-) – CommonsWare Feb 17, 2012 at 17:40 @JRC question is a good one. Is it possible to use startForeground() without notification? – Snicolas Oct 12, 2012 at 1:51 @Snicolas: Thank you for pointing out a flaw in Android. I will work on getting this fixed. – CommonsWare Oct 12, 2012 at 15:19

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);
                @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, 2017 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, 2017 at 16:23

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;
                You can use ContextCompat.startForegroundService(Context,Intent) in your Activity which will do the right thing. (developer.android.com/reference/android/support/v4/content/…)
– Simon Featherstone
                Feb 22, 2018 at 17:54
                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, 2018 at 14:20
                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 developer.android.com/reference/android/app/…
– Vadim Kotov
                Jan 11, 2019 at 12:55
                the permission step by step please.... if anything different from the usual one. :D @VadimKotov
– gumuruh
                Apr 26, 2022 at 3:48
                in android 12 startforgroundservice() causes ForegroundServiceStartNotAllowedException  . do anyone know a solution ?
– Liya
                Nov 30, 2022 at 9:49
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

If you remove the notification calling stopForeground(true) you are cancelling the startforeground service – sdelvalle57 Sep 30, 2015 at 17:13

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.

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

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

    //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" />
    

    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)

    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.

    I hope you're talking about the current question. Otherwise, there is no such rule in Stackoverflow community – Farid Sep 7, 2019 at 8: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 9, 2019 at 18:40

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

    @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);
    
  •  
    推荐文章