android — Context.startForegroundService () тогда не вызывал Service.startForeground ()" />

Context.startForegroundService () тогда не вызывал Service.startForeground ()

Я использую класс Service в ОС Android O.

Я планирую использовать Service в фоновом режиме.

Рекомендация Android гласит, что startService должен использовать startForegroundService.

Если вы используете startForegroundService, Service выдает Context.startForegroundService() не вызывал ошибку Service.startForeground().

Что с этим не так?

114 голосов | спросил NiceGuy 8 J0000006Europe/Moscow 2017, 05:15:46

21 ответ


0

Из документов Google на Изменения в поведении Android 8.0

  

Система позволяет приложениям вызывать Context.startForegroundService (), даже если приложение находится в фоновом режиме. Однако приложение должно вызвать метод startForeground () этой службы в течение пяти секунд после создания службы.

Решение: Вызовите startForeground() в onCreate() для Service, который вы используете Context.startForegroundService()

См. также: Пределы выполнения фона для Android 8.0 (Oreo)

ответил zhuzhumouse 12 J000000Wednesday17 2017, 05:51:28
0

Я позвонил ContextCompat.startForegroundService(this, intent), чтобы запустить службу, а затем

В службе onCreate

 @Override
 public void onCreate() {
        super.onCreate();

        if (Build.VERSION.SDK_INT >= 26) {
            String CHANNEL_ID = "my_channel_01";
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    "Channel human readable title",
                    NotificationManager.IMPORTANCE_DEFAULT);

            ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

            Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle("")
                    .setContentText("").build();

            startForeground(1, notification);
        }
}
ответил humazed 27 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowWed, 27 Sep 2017 17:04:19 +0300 2017, 17:04:19
0

Почему эта проблема возникает, потому что платформа Android не может гарантировать, что ваш сервис будет запущен в течение 5 секунд, но, с другой стороны, среда имеет строгие ограничения на уведомление переднего плана, которое должно быть запущено в течение 5 секунд, без проверки того, пыталась ли инфраструктура запустить службу.

Это определенно проблема с фреймворком, но не все разработчики, сталкивающиеся с этой проблемой, делают все возможное:

  1. startForeground уведомление должно быть как в onCreate, так и в onStartCommand, потому что, если ваша служба уже создана и каким-то образом ваша деятельность пытается запустить ее снова, onCreate вызываться не будет.

  2. идентификатор уведомления не должен быть равен 0, иначе произойдет такой же сбой, даже если это не та же причина.

  3. stopSelf нельзя вызывать перед startForeground.

Со всем вышеприведенным 3 эта проблема может быть немного уменьшена, но все же не является исправлением, реальное исправление или, скажем так, обходной путь - понизить целевую версию SDK до 25.

И обратите внимание, что, скорее всего, Android P по-прежнему будет нести эту проблему, потому что Google отказывается даже понимать, что происходит, и не считает, что это их вина, прочитайте # 36 здесь: https://issuetracker.google.com/issues/76112072 .

ответил ZhouX 5 J0000006Europe/Moscow 2018, 06:17:10
0

Ваше приложение будет зависать, если вы позвоните Context.startForegroundService(...), а затем вызовете Context.stopService(...) до вызова Service.startForeground(...).

У меня есть четкое подтверждение: https : //github.com/paulpv/ForegroundServiceAPI26/blob/repro/app/src/main/java/com/github/paulpv/foregroundserviceapi26/MainService.kt#L28

Я открыл ошибку на этом: https://issuetracker.google.com/issues/76112072

Несколько ошибок по этому поводу были открыты и закрыты. Не исправят.

Надеюсь, что мой с четкими шагами repro сделает разрез.

ответил swooby 22 MaramThu, 22 Mar 2018 02:39:22 +03002018-03-22T02:39:22+03:0002 2018, 02:39:22
0

Я исследовал это в течение нескольких дней и получил решение. Теперь в Android O вы можете установить ограничение фона, как показано ниже

Служба, которая вызывает класс обслуживания

Intent serviceIntent = new Intent(SettingActivity.this,DetectedService.class);
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){

                        SettingActivity.this.startForegroundService(serviceIntent);
                    }else{
                        startService(serviceIntent);
                    }

и класс обслуживания должен быть как

public class DetectedService extends Service { 
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        int NOTIFICATION_ID = (int) (System.currentTimeMillis()%10000);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(NOTIFICATION_ID, new Notification.Builder(this).build());
        }


        // Do whatever you want to do here
    }
}
ответил Ahmad Arslan 5 PMpThu, 05 Apr 2018 16:27:24 +030027Thursday 2018, 16:27:24
0

Просто один на один, потому что я потратил слишком много часов на это. Я продолжал получать это исключение, даже несмотря на то, что я первым делом вызывал startForeground(..) в onCreate(..). В конце концов я обнаружил, что проблема была вызвана использованием NOTIFICATION_ID = 0. Использование любого другого значения, кажется, исправит это.

ответил tobalr 16 Maypm18 2018, 23:01:52
0

Эта ошибка также возникает в Android 8+, когда Service.startForeground (int id, уведомление Notification) вызывается, а для id установлено значение 0.

  

id int: идентификатор для этого уведомления согласно NotificationManager.notify (int, Notification); не должно быть 0 .

ответил almisoft 1 J0000006Europe/Moscow 2018, 10:51:12
0

https: //разработчик. android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)

  

Аналогично startService (Intent), но с неявным обещанием, что   Служба будет вызывать startForeground (int, android.app.Notification) один раз   начинается бег. Сервису предоставляется количество времени, сопоставимое   для интервала ANR, чтобы сделать это, в противном случае система будет   автоматически остановить службу и объявить приложение ANR.

     

В отличие от обычного startService (Intent), этот метод можно использовать при   в любое время, независимо от того, находится ли   состояние переднего плана.

убедитесь, что вы вызываете Service.startForeground(int, android.app.Notification) для onCreate (), чтобы убедиться, что он будет вызван ... если у вас есть какие-либо условия, которые может помешать вам сделать это, тогда вам лучше использовать обычный Context.startService(Intent) и вызвать Service.startForeground(int, android.app.Notification) самостоятельно.

Похоже, что Context.startForegroundService() добавляет сторожевой таймер, чтобы убедиться, что вы вызвали Service.startForeground(int, android.app.Notification) до того, как он был уничтожен ...

ответил Alécio Carvalho 12 Jpm1000000pmFri, 12 Jan 2018 13:35:55 +030018 2018, 13:35:55
0

Так много ответов, но ни один не помог в моем случае.

Я запустил такой сервис.

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

И в моем сервисе в onStartCommand

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

И не забывайте устанавливать NOTIFICATION_ID ненулевым

  

приватная статическая конечная строка ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel";       private static final int NOTIFICATION_ID = 555;

ТАК все было отлично, но все равно зависало на 8.1, причина была как ниже.

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            stopForeground(true);
        } else {
            stopForeground(true);
        }

Я вызвал остановку переднего плана с удалением уведомлений, но как только служба удаления уведомлений стала фоновой, фоновая служба не может работать в Android O из фона. началось после получения толчка.

Волшебное слово

  stopSelf();

До сих пор, по любой причине, что ваш сервис не работает, следуйте всем вышеперечисленным шагам и наслаждайтесь.

ответил sandy 11 J0000006Europe/Moscow 2018, 21:53:23
0

Проблема с Android O API 26

Если вы немедленно остановите службу (так что ваша служба на самом деле не работает (формулировка /понимание) и вы находитесь в интервале ANR, вам все равно необходимо вызвать startForeground перед stopSelf

https://plus.google.com/116630648530850689477/posts/L2rn4T6SAJ5

Опробовал этот подход, но он по-прежнему выдает ошибку: -

if (Util.SDK_INT > 26) {
    mContext.startForegroundService(playIntent);
} else {
    mContext.startService(playIntent);
}

Я использую это, пока ошибка не будет устранена

mContext.startService(playIntent);

ответил Andy Cass 27 J0000006Europe/Moscow 2018, 12:35:03
0

У меня есть виджет , который выполняет относительно частые обновления, когда устройство находится в активном состоянии, и я видел тысячи аварий за несколько дней.

Триггер проблемы

Я даже заметил проблему даже на моем Pixel 3 XL, когда я не думал, что устройство вообще сильно загружено. И все пути к кодам были покрыты startForeground(). Но потом я понял, что во многих случаях мой сервис выполняет работу очень быстро. Я полагаю, что причиной моего приложения стало то, что служба заканчивала работу до того, как система фактически успела показать уведомление.

Обходной путь /решение

Мне удалось избавиться от всех сбоев. Я удалил вызов stopSelf(). (я думал о том, чтобы отложить остановку, пока не был уверен, что было показано уведомление, но я не хочу, чтобы пользователь видел уведомление, если в этом нет необходимости.) Когда служба неактивна в течение минуты или система обычно удаляет ее, не вызывая никаких исключений.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    stopForeground(true);
} else {
    stopSelf();
}
ответил Roy Solberg 21 32018vEurope/Moscow11bEurope/MoscowWed, 21 Nov 2018 00:44:10 +0300 2018, 00:44:10
0

Я столкнулся с той же проблемой, и, потратив время на поиск солутонов, вы можете попробовать код ниже. Если вы используете Service, поместите этот код в onCreate, иначе используйте Intent Service затем поместите этот код в 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);
    }
ответил Sambhaji Karad 9 AMpMon, 09 Apr 2018 10:20:28 +030020Monday 2018, 10:20:28
0

Даже после вызова startForeground в Service, происходит сбой на некоторых устройствах, если мы вызываем stopService непосредственно перед onCreate называется. Итак, я исправил эту проблему, запустив службу с дополнительным флагом:

Intent intent = new Intent(context,
                YourService.class);
intent.putExtra("request_stop", true);
context.startService(intent);

и добавил проверку в onStartCommand, чтобы увидеть, был ли он фактически остановлен:

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

    //call startForeground first
    boolean stopService = false;
    if (intent != null) {
        stopService = intent.getBooleanExtra("request_stop", false);
    }
    if (stopService) {
        stopSelf();
        return START_STICKY;
    }
    //Continue with the background task
    return START_STICKY;
}

P.S. Если служба на самом деле не была запущена, она сначала запустит службу, что является дополнительной нагрузкой.

ответил Gaurav Singla 22 J0000006Europe/Moscow 2018, 10:21:06
0

Я просто проверяю PendingIntent на ноль или нет перед вызовом   context.startForegroundService(service_intent) функция.

это работает для меня

PendingIntent pendingIntent=PendingIntent.getBroadcast(context,0,intent,PendingIntent.FLAG_NO_CREATE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && pendingIntent==null){
            context.startForegroundService(service_intent);
        }
        else
        {
            context.startService(service_intent);
        }
}
ответил SaimumIslam27 6 22018vEurope/Moscow11bEurope/MoscowTue, 06 Nov 2018 07:14:52 +0300 2018, 07:14:52
0

У меня есть решение этой проблемы. Я проверил это исправление в своем собственном приложении (300 КБ + DAU), которое может уменьшить как минимум 95% таких аварий, но все еще не может на 100% избежать этой проблемы.

Эта проблема возникает, даже если вы уверены, что вызываете startForeground () сразу после запуска службы, как это задокументировано Google. Это может быть связано с тем, что процесс создания и инициализации службы во многих сценариях уже стоит более 5 секунд, а затем независимо от того, когда и где вы вызываете метод startForeground (), этот сбой неизбежен.

Мое решение состоит в том, чтобы гарантировать, что startForeground () будет выполняться в течение 5 секунд после метода startForegroundService (), независимо от того, сколько времени потребуется для создания и инициализации службы. Вот подробное решение.

  1. Не используйте startForegroundService, используйте bindService () с флагом auto_create. Он будет ждать инициализации сервиса. Вот код, мой пример сервиса MusicService:

    final Context applicationContext = context.getApplicationContext();
    Intent intent = new Intent(context, MusicService.class);
    applicationContext.bindService(intent, new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            if (binder instanceof MusicBinder) {
                MusicBinder musicBinder = (MusicBinder) binder;
                MusicService service = musicBinder.getService();
                if (service != null) {
                    // start a command such as music play or pause.
                    service.startCommand(command);
                    // force the service to run in foreground here.
                    // the service is already initialized when bind and auto_create.
                    service.forceForeground();
                }
            }
            applicationContext.unbindService(this);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }, Context.BIND_AUTO_CREATE);
    
  2. Тогда вот реализация MusicBinder:

    /**
     * Use weak reference to avoid binder service leak.
     */
     public class MusicBinder extends Binder {
    
         private WeakReference<MusicService> weakService;
    
         /**
          * Inject service instance to weak reference.
          */
         public void onBind(MusicService service) {
             this.weakService = new WeakReference<>(service);
         }
    
         public MusicService getService() {
             return weakService == null ? null : weakService.get();
         }
     }
    
  3. Самая важная часть, реализация MusicService, метод forceForeground () гарантирует, что метод startForeground () вызывается сразу после startForegroundService ():

    public class MusicService extends MediaBrowserServiceCompat {
    ...
        private final MusicBinder musicBind = new MusicBinder();
    ...
        @Override
        public IBinder onBind(Intent intent) {
            musicBind.onBind(this);
            return musicBind;
        }
    ...
        public void forceForeground() {
            // API lower than 26 do not need this work around.
            if (Build.VERSION.SDK_INT >= 26) {
                Intent intent = new Intent(this, MusicService.class);
                // service has already been initialized.
                // startForeground method should be called within 5 seconds.
                ContextCompat.startForegroundService(this, intent);
                Notification notification = mNotificationHandler.createNotification(this);
                // call startForeground just after startForegroundService.
                startForeground(Constants.NOTIFICATION_ID, notification);
            }
        }
    }
    
  4. Если вы хотите запустить фрагмент кода шага 1 в ожидающем намерении, например, если вы хотите запустить службу переднего плана в виджете (щелчок по кнопке виджета) без открытия приложения, вы можете заключить фрагмент кода в приемнике широковещания и запуск события широковещания вместо команды запуска службы.

Это все. Надеюсь, поможет. Удачи.

ответил Hexise 13 22018vEurope/Moscow11bEurope/MoscowTue, 13 Nov 2018 20:09:01 +0300 2018, 20:09:01
0

Пожалуйста, не вызывайте никакие StartForgroundServices внутри метода onCreate () , вам нужно вызывать службы StartForground в onStartCommand () после создания рабочего потока, в противном случае вы получите ANR всегда, поэтому, пожалуйста, не пишите сложный логин в основной ветке onStartCommand () ;

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

    }
}
ответил Shalu Gupta 31 MonEurope/Moscow2018-12-31T14:41:56+03:00Europe/Moscow12bEurope/MoscowMon, 31 Dec 2018 14:41:56 +0300 2018, 14:41:56
0

Я знаю, что это поздний ответ, но, думаю, это могло бы помочь в будущем, я просто использовал JobIntentService вместо IntentService, который включает его JobScheduler и обрабатывает все для меня. посмотрите на этот пример

ответил raed 8 PM00000060000003531 2018, 18:21:35
0

Я исследовал эту проблему, и это то, что я обнаружил до сих пор. Этот сбой может произойти, если у нас есть код, подобный этому:

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

Исключение выдается в следующем блоке кода:

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

Этот метод выполняется перед onCreate() из MyForegroundService потому что Android планирует создание службы в обработчике основного потока, но bringDownServiceLocked вызывается для BinderThread, что является условием гонки. Это означает, что у MyForegroundService не было возможности вызвать startForeground, что приведет к сбою.

Чтобы исправить это, мы должны убедиться, что bringDownServiceLocked не вызывается перед onCreate() из 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));
    }
}

Используя липкие трансляции, мы следим за тем, чтобы трансляция не терялась, и stopReceiver получает намерение остановить, как только оно был зарегистрирован в onCreate() из MyForegroundService. К этому времени мы уже вызвали startForeground(...). Мы также должны удалить эту липкую трансляцию, чтобы в следующий раз не было уведомлено stopReceiver.

Обратите внимание , что метод sendStickyBroadcast устарел, и я использую его только как временное решение проблемы эта проблема.

ответил makovkastar 22 42018vEurope/Moscow11bEurope/MoscowThu, 22 Nov 2018 13:30:25 +0300 2018, 13:30:25
0

Я исправил проблему с запуском службы с помощью startService(intent) вместо Context.startForeground() и вызов startForegound() сразу после super.OnCreate(). Кроме того, если вы запускаете службу при загрузке, вы можете запустить Activity, которая запускает службу при загрузке. Хотя это не постоянное решение, оно работает.

ответил mystogan 7 Jpm1000000pmMon, 07 Jan 2019 16:06:48 +030019 2019, 16:06:48
0

Все это исчезнет, ​​если переписать службу для запуска с помощью bindService.

Пример того, как это сделать, можно увидеть по адресу: https://github.com/paulpv/ForegroundServiceAPI26/tree/bound

Различия в моей ветке "repro" можно увидеть по адресу: https://github.com/paulpv/ForegroundServiceAPI26/compare/репро ... связаны? расширить = 1

ответил swooby 5 Mayam18 2018, 05:23:12
0

Убедитесь, что все пути кода вызывают метод startForeground, например, код может генерировать исключение в методе onCreate вашего сервиса, которое препятствует вызову startForeground

   @Override
    public void onCreate() {
try{
}
catch(Exception e)
{
}
finally{
    startForeground(1, notificationbuilder.build());

}
    }
ответил Mohamed Gaafar 4 MarpmSun, 04 Mar 2018 17:58:29 +03002018-03-04T17:58:29+03:0005 2018, 17:58:29

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132