Context.startForegroundService() did not then call

2019-01-04 06:46发布

I am using Service Class on the Android O OS.

I plan to use the Service in the background.

The Android recommendation states that startService should use startForegroundService.

If you use startForegroundService, the Service throws a Context.startForegroundService() did not then call Service.startForeground() error.

What's wrong with this?

20条回答
再贱就再见
2楼-- · 2019-01-04 07:32

Why this issue is happening is because Android framework can't guarantee your service get started within 5 second but on the other hand framework does have strict limit on foreground notification must be fired within 5 seconds, without checking if framework had tried to start the service.

This is definitely a framework issue, but not all developers facing this issue are doing their best:

  1. startForeground a notification must be in both onCreate and onStartCommand, because if your service is already created and somehow your activity is trying to start it again, onCreate won't be called.

  2. notification ID must not be 0 otherwise same crash will happen even it's not same reason.

  3. stopSelf must not be called before startForeground.

With all above 3 this issue can be reduced a bit but still not a fix, the real fix or let's say workaround is to downgrade your target sdk version to 25.

And note that most likely Android P will still carry this issue because Google refuses to even understand what is going on and does not believe this is their fault, read #36 in here: https://issuetracker.google.com/issues/76112072.

查看更多
萌系小妹纸
3楼-- · 2019-01-04 07:32

Your app will crash if you call Context.startForegroundService(...) and then call Context.stopService(...) before Service.startForeground(...) is called.

I have a clear repro at: https://github.com/paulpv/ForegroundServiceAPI26/blob/repro/app/src/main/java/com/github/paulpv/foregroundserviceapi26/MainService.kt#L28

I have opened a bug on this: https://issuetracker.google.com/issues/76112072

Several bugs on this have been opened and closed Won't Fix.

Hopefully mine with clear repro steps will make the cut.

查看更多
我想做一个坏孩纸
4楼-- · 2019-01-04 07:32

I am facing same issue and after spending time found a solutons you can try below code. If your using Service then put this code in onCreate else your using Intent Service then put this code in onHandleIntent.

if (Build.VERSION.SDK_INT >= 26) {
        String CHANNEL_ID = "my_app";
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                "MyApp", NotificationManager.IMPORTANCE_DEFAULT);
        ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("")
                .setContentText("").build();
        startForeground(1, notification);
    }
查看更多
冷血范
5楼-- · 2019-01-04 07:36

Please don't call any StartForgroundServices inside onCreate() method, you have to call StartForground services in onStart() command after make the worker thread otherwise you will get ANR always , so please don't write complex login in main thread of onStatcommand();

public class Services extends Service {

private static final String ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel";
@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
                .setContentTitle(getString(R.string.app_name))
                .setContentText("SmartTracker Running")
                .setAutoCancel(true);
        Notification notification = builder.build();
        startForeground(0, notification);
        Log.e("home_button","home button");
    } else {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setContentTitle(getString(R.string.app_name))
                .setContentText("SmartTracker is Running...")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setAutoCancel(true);
        Notification notification = builder.build();
        startForeground(0, notification);
        Log.e("home_button_value","home_button_value");

    }
    return super.onStartCommand(intent, flags, startId);

}

}

查看更多
趁早两清
6楼-- · 2019-01-04 07:36

I know it's a late answer but, I think it could help in future, I just used JobIntentService instead of IntentService that include its JobScheduler and handle everything for me. look at this example

查看更多
爱情/是我丢掉的垃圾
7楼-- · 2019-01-04 07:36

I've been researching this issue and this is what I've discovered so far. This crash could happen if we have code similar to this:

MyForegroundService.java

public class MyForegroundService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(...);
    }
}

MainActivity.java

Intent serviceIntent = new Intent(this, MyForegroundService.class);
startForegroundService(serviceIntent);
...
stopService(serviceIntent);

The exception is thrown in the following block of the code:

ActiveServices.java

private final void bringDownServiceLocked(ServiceRecord r) {
    ...
    if (r.fgRequired) {
        Slog.w(TAG_SERVICE, "Bringing down service while still waiting for start foreground: "
                  + r);
        r.fgRequired = false;
        r.fgWaiting = false;
        mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                    AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
        mAm.mHandler.removeMessages(
                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
        if (r.app != null) {
            Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
            msg.obj = r.app;
            msg.getData().putCharSequence(
                ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
            mAm.mHandler.sendMessage(msg);
         }
    }
    ...
}

This method is executed before onCreate() of MyForegroundService because Android schedules the creation of the service on the main thread handler but bringDownServiceLocked is called on a BinderThread, wich is a race condition. It means that MyForegroundService didn't have a chance to call startForeground which will cause the crash.

To fix this we have to make sure that bringDownServiceLocked is not called before onCreate() of MyForegroundService.

public class MyForegroundService extends Service {

    private static final String ACTION_STOP = "com.example.MyForegroundService.ACTION_STOP";

    private final BroadcastReceiver stopReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            context.removeStickyBroadcast(intent);
            stopForeground(true);
            stopSelf();
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(...);
        registerReceiver(
            stopReceiver, new IntentFilter(ACTION_STOP));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(stopReceiver);
    }

    public static void stop(Context context) {
        context.sendStickyBroadcast(new Intent(ACTION_STOP));
    }
}

By using sticky broadcasts we make sure that the broadcast doesn't get lost and stopReceiver receives the stop intent as soon as it has been registered in onCreate() of MyForegroundService. By this time we have already called startForeground(...). We also have to remove that sticky broadcast to prevent stopReceiver being notified next time.

Please note that the method sendStickyBroadcast is deprecated and I use it only as a temporary workaround to fix this issue.

查看更多
登录 后发表回答