471

On application launch, app starts the service that should to do some network task. After targeting API level 26, my application fails to start service on Android 8.0 on background.

Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=my.app.tt/com.my.service }: app is in background uid UidRecord{90372b1 u0a136 CEM idle procs:1 seq(0,0,0)}

as I understand it related to: Background execution limits

The startService() method now throws an IllegalStateException if an app targeting Android 8.0 tries to use that method in a situation when it isn't permitted to create background services.

"in a situation when it isn't permitted" - what it's actually mean?? And how to fix it. I don't want to set my service as "foreground"

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
phnmnn
  • 12,813
  • 11
  • 47
  • 64
  • 8
    It means that you cannot start a service when your app is in the background – Tim Sep 27 '17 at 10:17
  • You may need to [Request Permissions at Run Time](https://developer.android.com/training/permissions/requesting.html). – Tigger Sep 27 '17 at 10:18
  • try firebase Job Dispatcher. – Mehta Sep 27 '17 at 10:22
  • 24
    this has nothing to do with runtime permissions – Tim Sep 27 '17 at 10:22
  • 25
    Use `startForegroundService()` instead of `startService()`. – frogatto Oct 11 '17 at 13:21
  • 2
    You can try to use targetSdkVersion 25 but compile with compileSdkVersion 26. This way you can use new classes from Android 8 and newest suppport library but your app will not be limited by Background Execution Limits. – Kacper Dziubek Jan 19 '18 at 10:18
  • 3
    @KacperDziubek That should work but is a temporary solution as it will be required to target SDK26 in fall of 2018. – RightHandedMonkey Jun 08 '18 at 21:04
  • @RightHandedMonkey Yes, it's true. When I wrote this comment it was not yet announced that Google Play will not allow to update apps targeted below SDK 26. – Kacper Dziubek Jun 12 '18 at 12:41
  • check this answer https://stackoverflow.com/a/52236155/6401241 – Radesh Sep 08 '18 at 14:19
  • I'm getting the exception on Android 8 even if I decrease target and compile sdk to 25 (or 23 for that matter). Is there any other temporary solution I can do until I rewrite my apps that would work on my android 8 phones? (I have to do some serious rewrites but in the meantime we'd need the apps.) – soger Mar 06 '19 at 11:11
  • I don't know what the hell was going on with that project, but I removed it and recreated the whole thing and now it works. It's just pathetic. – soger Mar 06 '19 at 12:29
  • I have a similar problem and it was fixed by adding 'setComponent(MYSERVICE)' to a starting intent. I didn't test it with API level 28 though. – user2305886 Jul 12 '19 at 01:29
  • Android O and above JobScheduler is recommended for background operations. https://stackoverflow.com/a/54570275/5217859 – abhi.nalavade Jul 29 '19 at 06:02

18 Answers18

336

I got solution. For pre-8.0 devices, you have to just use startService(), but for post-7.0 devices, you have to use startForgroundService(). Here is sample for code to start service.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(new Intent(context, ServedService.class));
    } else {
        context.startService(new Intent(context, ServedService.class));
    }

And in service class, please add the code below for notification:

@Override
public void onCreate() {
    super.onCreate();
    startForeground(1,new Notification());
}

Where O is Android version 26.

If you don't want your service to run in Foreground and want it to run in background instead, post Android O you must bind the service to a connection like below:

Intent serviceIntent = new Intent(context, ServedService.class);
context.startService(serviceIntent);
context.bindService(serviceIntent, new ServiceConnection() {
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         //retrieve an instance of the service here from the IBinder returned 
         //from the onBind method to communicate with 
     }

     @Override
     public void onServiceDisconnected(ComponentName name) {
     }
}, Context.BIND_AUTO_CREATE);
Salam El-Banna
  • 3,784
  • 1
  • 22
  • 34
Sagar Kacha
  • 8,338
  • 4
  • 18
  • 27
  • 15
    A foreground service is something that the user will be aware of and that needs a notification. It will also ANR if it runs too long. So it's not really a suitable answer if the app is already running in the background. – Simon Hutton Dec 19 '17 at 17:02
  • 90
    There is a `ContextCompat.startForegroundService(...)` in support lib that can be used instead. – jayeffkay Dec 28 '17 at 11:55
  • 1
    **android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()** – Choletski Feb 12 '18 at 08:10
  • 18
    I also agree that this is not a solution. It's a workaround and it helps, but the background limits in Oreo were introduced for a reason. Bypassing those limits this way definitely isn't the correct approach (even though it works). The best way is to use JobScheduler (refer to the accepted answer). – Vratislav Jindra Feb 12 '18 at 18:20
  • android.app.RemoteServiceException: Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: Notification(channel=null pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x40 color=0x00000000 vis=PRIVATE) – Vishal Patoliya ツ Mar 28 '18 at 05:33
  • 7
    I don't think it will be a good user experience if you must show an empty foreground notification. Considering the fact that u must. -- Android 8.0 introduces the new method startForegroundService() to start a new service in the foreground. After the system has created the service, the app has five seconds to call the service's startForeground() method to show the new service's user-visible notification. If the app does not call startForeground() within the time limit, the system stops the service and declares the app to be ANR. – heeleeaz May 01 '18 at 06:10
  • 1
    Thank you, this solved my issue. Though we should look into going towards JobIntentService as explained in other answers as well! – yUdoDis Jul 23 '18 at 06:17
  • 3
    It seems that `new Notificaction()` doesn't work from Android 8.1; You should create the channel for notification: stackoverflow.com/a/47533338/1048087 – Prizoff Jul 29 '18 at 12:59
  • 3
    Also, from the docs: Apps targeting API Build.VERSION_CODES.P or later must request the permission Manifest.permission.FOREGROUND_SERVICE in order to use this API. – Prizoff Jul 29 '18 at 13:02
  • 2
    Is there a check I can rather do to see if the app is in the foreground or not? if not, don't start the service? – Pierre Nov 27 '18 at 09:22
  • 1
    You cant start services from background and startForegroundService() is broken in Oreo and Pie. Also, i'm facing crashes in JobScheduler on some devices. Workmanager uses job scheduler under the hood so not a solution for me. Anyone has a better solution? – Prasad Pawar Jan 02 '19 at 09:34
  • 1
    I found it way better than the job scheduler. Which is too complicated, besides I'm not even sure it does well what I want. I just want a small service that runs in the background and receives some kind of system notification. The job scheduler will probably do it but introduce additional delays. The foreground service OTOH just gives a short non-intrusive notification to the user. I can live with that. – VSim May 13 '19 at 10:18
  • Does it mean that I have to check whether API >= 26 and if yes, then call `startForegroundService()`, otherwise call `startService()`? – scarface May 17 '19 at 09:07
  • this approach exactly will give you an error: Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: null – Tamim Attafi Jan 01 '20 at 11:29
  • 1
    I think it depends. For example, if you work with sockets, workaround is solution – Autumn_Cat Mar 31 '20 at 18:52
225

The permitted situations are a temporary whitelist where the background service behaves the same as before Android O.

Under certain circumstances, a background app is placed on a temporary whitelist for several minutes. While an app is on the whitelist, it can launch services without limitation, and its background services are permitted to run. An app is placed on the whitelist when it handles a task that's visible to the user, such as:

  • Handling a high-priority Firebase Cloud Messaging (FCM) message.
  • Receiving a broadcast, such as an SMS/MMS message.
  • Executing a PendingIntent from a notification.
  • Starting a VpnService before the VPN app promotes itself to the foreground.

Source: https://developer.android.com/about/versions/oreo/background.html

So in other words if your background service does not meet the whitelist requirements you have to use the new JobScheduler. It's basically the same as a background service, but it gets called periodically instead of running in the background continuously.

If you're using an IntentService, you can change to a JobIntentService. See @kosev's answer below.

JohnnyLambada
  • 12,700
  • 11
  • 57
  • 61
Murat Karagöz
  • 35,401
  • 16
  • 78
  • 107
  • I am getting a crash after I want to start service just after I receive GCM message of "high" prio. I still use GCM: "com.google.android.gms:play-services-gcm:11.4.2", not 'com.google.firebase:firebase-messaging:11.4.2'. Not sure it matters though.. – Alex Radzishevsky Oct 30 '17 at 13:42
  • "It's basically the same as a background service, but it gets called periodically instead of running in the background continuously." - not sure what you mean by this, as Android services have never executed continuously. They start, run, then shut down. – Melllvar Nov 07 '17 at 03:57
  • 2
    Is the `FirebaseInstanceIdService ` and its `onTokenRefresh` method a high-priority FCM message? – Cord Rehn Nov 28 '17 at 01:43
  • @phnmnn no, GCMTaskService doesn't really follow FCM hence they dont work. – Abhinav Upadhyay Jan 20 '18 at 07:24
  • @CordRehn yes, `FirebaseInstanceIdService` will work, no worries there. Follow proper documentation from [here](https://firebase.google.com) – Abhinav Upadhyay Jan 20 '18 at 07:30
  • The easiest way to use the new JobScheduler is through JobIntentService. See my answer. – kosev Apr 15 '18 at 20:24
  • 5
    Shouldn't you use WorkManager (here: https://developer.android.com/topic/libraries/architecture/workmanager ) instead of JobScheduler or others ? I mean this: https://youtu.be/IrKoBFLwTN0 – android developer Jun 04 '18 at 14:09
  • +1. Given the fact that "Receiving a broadcast" is a whitelist situation, deprecating the WakefulBroadcastReceiver with justification that this class is "no longer generally useful" doesn't make sense to me, because it's also a BroadcastReceiver. The deprecation note is here: https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver – Diego dos Santos Aug 08 '18 at 15:07
  • I have an app that doesn't do any of the things in the list to be whitelisted and still doesn't throw any exceptions when it calls startServices() being in the background. Please check my question: https://stackoverflow.com/questions/52316856/oreo-startservice-doesnt-throw-illegalstateexception-when-called-in-backgrou – makovkastar Oct 01 '18 at 15:48
  • 1
    SO is pretty good, but I have been misled before. Is it really true that I have to use JobScheduler? Are all the people talking about startForegroundService/startForeground on something? – Gerry Mar 06 '19 at 22:07
104

The best way is to use JobIntentService which uses the new JobScheduler for Oreo or the old services if not available.

Declare in your manifest:

<service android:name=".YourService"
         android:permission="android.permission.BIND_JOB_SERVICE"/>

And in your service you have to replace onHandleIntent with onHandleWork:

public class YourService extends JobIntentService {

    public static final int JOB_ID = 1;

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, YourService.class, JOB_ID, work);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        // your code
    }

}

Then you start your service with:

YourService.enqueueWork(context, new Intent());
kosev
  • 2,125
  • 1
  • 20
  • 18
  • 1
    @ralphgabb https://developer.android.com/about/versions/oreo/background#intentservice-is-subject-to-these-restrictions – Dr.jacky May 22 '18 at 09:29
  • How you are able to call a non-static method inside a static method? Can you please explain? – Maddy Sep 28 '18 at 12:27
  • 1
    @Maddy `enqueueWork(...)` is a static method as well. – hgoebl Oct 06 '18 at 11:01
  • 3
    Where would you call YourService.enqueueWork(context, new Intent()); ? From broadcast receiver? – TheLearner Oct 29 '18 at 14:42
  • I don't believe that this is the easiest solution. See my comment below about WorkManager. It uses the JobIntentService when appropriate, but it has a lot less boiler plate. – TALE Mar 07 '19 at 16:16
  • JobIntentService is deprecated. Better go with this suggestion https://stackoverflow.com/questions/68696064/android-jobintentservice-is-deprecated – Baskar PC Aug 25 '22 at 03:47
38

If the service is running in a background thread by extending IntentService, you can replace IntentService with JobIntentService which is provided as part of Android Support Library

The advantage of using JobIntentService is, it behaves as an IntentService on pre-O devices and on O and higher, it dispatches it as a job

JobScheduler can also be used for periodic/on demand jobs. But, ensure to handle backward compatibility as JobScheduler API is available only from API 21

CopsOnRoad
  • 237,138
  • 77
  • 654
  • 440
Harini S
  • 563
  • 4
  • 8
  • 1
    The problem with JobIntentService is that Android can schedule your work rather arbitrarily, and it can't be started implicitly without some tinkering around, unlike an IntentService. See https://stackoverflow.com/questions/52479262/start-a-jobintentservice-implicitly – kilokahn Jan 04 '19 at 08:00
21

Yeah, that's because you can't start services in the background anymore on API 26. So you can start ForegroundService above API 26.

You'll have to use

ContextCompat.startForegroundService(...)

and post a notification while processing the leak.

P.K
  • 263
  • 2
  • 9
  • 2
    The OP specifically said he doesn't want as foreground. This should be put as a comment or as part of a more complete answer. – Ricardo A. Dec 27 '19 at 12:53
13

As @kosev said in his answer you can use JobIntentService. But I use an alternative solution - I catch IllegalStateException and start the service as foreground. For example, this function starts my service:

@JvmStatic
protected fun startService(intentAction: String, serviceType: Class<*>, intentExtraSetup: (Intent) -> Unit) {
    val context = App.context
    val intent = Intent(context, serviceType)
    intent.action = intentAction
    intentExtraSetup(intent)
    intent.putExtra(NEED_FOREGROUND_KEY, false)

    try {
        context.startService(intent)
    }
    catch (ex: IllegalStateException) {
        intent.putExtra(NEED_FOREGROUND_KEY, true)
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent)
        }
        else {
            context.startService(intent)
        }
    }
}

and when I process Intent I do such thing:

override fun onHandleIntent(intent: Intent?) {
    val needToMoveToForeground = intent?.getBooleanExtra(NEED_FOREGROUND_KEY, false) ?: false
    if(needToMoveToForeground) {
        val notification = notificationService.createSyncServiceNotification()
        startForeground(notification.second, notification.first)

        isInForeground = true
    }

    intent?.let {
        getTask(it)?.process()
    }
}
Alex Shevelev
  • 681
  • 7
  • 14
  • I like your try catch solution. For me it is a solution because sometimes `context.startService` works in background - sometimes not - this looks like the only best way otherwise you have to implement more code in your main class `extending Application` and `implementing ActivityLifecycleCallbacks` and keep track whether the app is in the foreground or background and start your intent accordingly. – Pierre May 15 '19 at 06:31
  • Can this exception be Catched? – thecr0w Jan 10 '20 at 05:03
  • 3
    there is one potential mistake - while `context.startService(intent)` is being caught by `try/catch` in `try` block, there is one more time the same code line repeated in `catch` block, which could potentially cause a crash. – Stan Mar 05 '21 at 11:47
8

I see a lot of responses that recommend just using a ForegroundService. In order to use a ForegroundService there has to be a notification associated with it. Users will see this notification. Depending on the situation, they may become annoyed with your app and uninstall it.

The easiest solution is to use the new Architecture Component called WorkManager. You can check out the documentation here: https://developer.android.com/topic/libraries/architecture/workmanager/

You just define your worker class that extends Worker.

public class CompressWorker extends Worker {

    public CompressWorker(
        @NonNull Context context,
        @NonNull WorkerParameters params) {
        super(context, params);
    }

    @Override
    public Worker.Result doWork() {

        // Do the work here--in this case, compress the stored images.
        // In this example no parameters are passed; the task is
        // assumed to be "compress the whole library."
        myCompress();

        // Indicate success or failure with your return value:
        return Result.SUCCESS;

        // (Returning RETRY tells WorkManager to try this task again
        // later; FAILURE says not to try again.)
    }
}

Then you schedule when you want to run it.

    OneTimeWorkRequest compressionWork = 
        new OneTimeWorkRequest.Builder(CompressWorker.class)
            .build();
    WorkManager.getInstance().enqueue(compressionWork);

Easy! There are a lot of ways you can configure workers. It supports recurring jobs and you can even do complex stuff like chaining if you need it. Hope this helps.

TALE
  • 960
  • 13
  • 22
  • 3
    Currently WorkManager is still alpha. – pzulw Nov 14 '18 at 19:07
  • 3
    March 05, 2019 - WorkManager 1.0.0 stable release. – phnmnn Mar 07 '19 at 08:30
  • should use WorkManager instead of using interservice or JobIntentService – sivaBE35 Mar 25 '19 at 07:47
  • 1
    `WorkManager is intended for tasks that are deferrable—that is, not required to run immediately`... it might be easiest, however, my app needs a background service that executes the users' requests immediately ! – Someone Somewhere May 09 '19 at 10:42
  • 1
    If you require the task to be completed immediately, then you should use a foreground service. The user will see a notification and know that you are doing work. Check out the docs if you need help deciding what to use. They have a pretty good guide for background processing. https://developer.android.com/guide/background/ – TALE May 09 '19 at 17:28
8

Alternate solution by using JobScheduler, it can start service in background in regular interval of time.

Firstly make class named as Util.java

import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;

public class Util {
// schedule the start of the service every 10 - 30 seconds
public static void schedulerJob(Context context) {
    ComponentName serviceComponent = new ComponentName(context,TestJobService.class);
    JobInfo.Builder builder = new JobInfo.Builder(0,serviceComponent);
    builder.setMinimumLatency(1*1000);    // wait at least
    builder.setOverrideDeadline(3*1000);  //delay time
    builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);  // require unmetered network
    builder.setRequiresCharging(false);  // we don't care if the device is charging or not
    builder.setRequiresDeviceIdle(true); // device should be idle
    System.out.println("(scheduler Job");

    JobScheduler jobScheduler = null;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        jobScheduler = context.getSystemService(JobScheduler.class);
    }
    jobScheduler.schedule(builder.build());
   }
  }

Then, make JobService class named as TestJobService.java

import android.app.job.JobParameters;
import android.app.job.JobService;
import android.widget.Toast;
 
  /**
   * JobService to be scheduled by the JobScheduler.
   * start another service
   */ 
public class TestJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
    Util.schedulerJob(getApplicationContext()); // reschedule the job
    Toast.makeText(this, "Bg Service", Toast.LENGTH_SHORT).show();
    return true;
}

@Override
public boolean onStopJob(JobParameters params) {
    return true;
  }
 }

After that BroadCast Receiver class named ServiceReceiver.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

 public class ServiceReceiver extends BroadcastReceiver {
 @Override
public void onReceive(Context context, Intent intent) {
    Util.schedulerJob(context);
 }
}

Update Manifest file with service and receiver class code

<receiver android:name=".ServiceReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <service
        android:name=".TestJobService"
        android:label="Word service"
        android:permission="android.permission.BIND_JOB_SERVICE" >

    </service>

Left main_intent launcher to mainActivity.java file which is created by default, and changes in MainActivity.java file are

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Util.schedulerJob(getApplicationContext());
  }
 }

WOOAAH!! Background Service starts without Foreground service

[Edit]: You can use Work Manager for any type of background tasks in Android.

Anshul1507
  • 529
  • 6
  • 14
6

From the firebase release notes, they state that support for Android O was first released in 10.2.1 (although I'd recommend using the most recent version).

please add new firebase messaging dependencies for android O

compile 'com.google.firebase:firebase-messaging:11.6.2'

upgrade google play services and google repositories if needed.

Dhaval Jivani
  • 9,467
  • 2
  • 48
  • 42
  • This does not answer the question, nor the question has anything to do with firebase. It should be put as a comment. – Ricardo A. Dec 27 '19 at 12:35
6

If any intent was previously working fine when the app is in the background, it won't be the case any more from Android 8 and above. Only referring to intent which has to do some processing when app is in the background.

The below steps have to be followed:

  1. Above mentioned intent should be using JobIntentService instead of IntentService.
  2. The class which extends JobIntentService should implement the - onHandleWork(@NonNull Intent intent) method and should have below the method, which will invoke the onHandleWork method:

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, xyz.class, 123, work);
    }
    
  3. Call enqueueWork(Context, intent) from the class where your intent is defined.

    Sample code:

    Public class A {
    ...
    ...
        Intent intent = new Intent(Context, B.class);
        //startService(intent); 
        B.enqueueWork(Context, intent);
    }
    

The below class was previously extending the Service class

Public Class B extends JobIntentService{
...

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, B.class, JobId, work);
    }

    protected void onHandleWork(@NonNull Intent intent) {
        ...
        ...
    }
}
  1. com.android.support:support-compat is needed for JobIntentService - I use 26.1.0 V.

  2. Most important is to ensure the Firebase libraries version is on at least 10.2.1, I had issues with 10.2.0 - if you have any!

  3. Your manifest should have the below permission for the Service class:

    service android:name=".B"
    android:exported="false"
    android:permission="android.permission.BIND_JOB_SERVICE"
    

Hope this helps.

0xCursor
  • 2,242
  • 4
  • 15
  • 33
c_c
  • 81
  • 2
  • 7
4

Due to controversial votes on this answer (+4/-4 as of this edit), PLEASE LOOK AT THE OTHER ANSWERS FIRST AND USE THIS ONLY AS A LAST RESORT. I only used this once for a networking app that runs as root and I agree with the general opinion that this solution should not be used under normal circumstances.

Original answer below:

The other answers are all correct, but I'd like to point out that another way to get around this is to ask user to disable battery optimizations for your app (this isn't usually a good idea unless your app is system related). See this answer for how to request to opt out of battery optimizations without getting your app banned in Google Play.

You should also check whether battery optimizations are turned off in your receiver to prevent crashes via:

if (Build.VERSION.SDK_INT < 26 || getSystemService<PowerManager>()
        ?.isIgnoringBatteryOptimizations(packageName) != false) {
    startService(Intent(context, MyService::class.java))
} // else calling startService will result in crash
Mygod
  • 2,077
  • 1
  • 19
  • 43
  • 1
    Asking your users to let you have a free pass using as much battery as possible isn't a good solution. Consider converting your code to a more battery friendly solution. Your users will thank you. – TALE Nov 14 '18 at 14:30
  • 8
    @TALE Not every background service can be made battery friendly using `JobScheduler` and stuff. Some of the apps need to work at a lower level than typical syncing applications. This is an alternative solution when that doesn't work. – Mygod Nov 15 '18 at 06:51
4

If you are running your code on 8.0 then application will crash. So start the service in the foreground. If below 8.0 use this :

Intent serviceIntent = new Intent(context, RingtonePlayingService.class);
context.startService(serviceIntent);

If above or 8.0 then use this :

Intent serviceIntent = new Intent(context, RingtonePlayingService.class);
ContextCompat.startForegroundService(context, serviceIntent );
  • 1
    It is recommended to only use Foreground services for cases where the user needs to be aware that a service is running. The typical example is for playing music in the background. There are other cases that make sense, but you shouldn't just convert all of your services to Foreground services. Consider converting your services to use WorkManager from Google's Architectural components when you just need to do some work in the background and be guaranteed that it will run. – TALE Nov 14 '18 at 16:39
  • startForegroundService requires permission, otherwise `java.lang.SecurityException: Permission Denial: startForeground from pid=13708, uid=10087 requires android.permission.FOREGROUND_SERVICE`. Fix at https://stackoverflow.com/a/52382711/550471 – Someone Somewhere May 09 '19 at 10:59
1

if you have integrated firebase messaging push notification then,

Add new/update firebase messaging dependencies for android O (Android 8.0), due to Background Execution Limits.

compile 'com.google.firebase:firebase-messaging:11.4.0'

upgrade google play services and google repositories if needed.

Update:

 compile 'com.google.firebase:firebase-messaging:11.4.2'
Samir Mangroliya
  • 39,918
  • 16
  • 117
  • 134
0

Use startForegroundService() instead of startService() and don't forget to create startForeground(1,new Notification()); in your service within 5 seconds of starting service.

cordeiro
  • 121
  • 1
  • 12
Arpit
  • 297
  • 1
  • 5
  • 13
  • 2
    It seems that new Notificaction() doesn't work from Android 8.1; You should create the channel for notification: https://stackoverflow.com/a/47533338/1048087 – Prizoff Jul 29 '18 at 12:55
0

it's actually happening because the phone is on offscreen, or you pressed the power button while starting the service. solution for this which worked for me is to start an activity and when it will go in onResume then start the service. in my case, it was booting up and starting a service.

0

I am very dissatisfied with the answers here. What if foreground service nor WorkManager fit the use case? I've come to a solution, where I use process scope and make sure to not include scope cancellation exception in the logging logic. Like so:

with(ProcessLifecycleOwner.get()) {
  lifecycleScope.launch {
    lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
      try {
        context.startService(context, Service::class.java)
      } catch (ex: CancellationException) {
        // app minimized, scope cancelled, do not log as error
      } catch (ex: IllegalStateException) {
        logToFirebase(ex)
      }
    }
  }
}

More detailed in this article https://medium.com/@lepicekmichal/android-background-service-without-hiccup-501e4479110f

Majkeee
  • 960
  • 1
  • 8
  • 28
0

You may try this code to avoid crash. As google developers said in issue tracker.

private val activityManager by lazy { getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager }

//due to https://issuetracker.google.com/issues/113122354
private fun isInForegroundByImportance(): Boolean {
    val importanceState = activityManager.runningAppProcesses.find {
        it.pid == android.os.Process.myPid()
    }?.importance ?: return false
    return importanceState >= RunningAppProcessInfo.IMPORTANCE_FOREGROUND
}

and usage

override fun onResume() {
    super.onResume()
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || isInForegroundByImportance()) {
        val intent = Intent(this, BluetoothScannerService::class.java)
        this.startService(intent)
    }
}
-1

i had this problem too

added this library

implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'

and reinstalled the app solved this for me

Parikshit Sharma
  • 307
  • 2
  • 14