Oreo: как поймать обновление местоположения из фона?

Я переношу свое приложение на oreo (так как сейчас это требуется для игры в Google), и теперь у меня возникает ошибка при запуске телефона:

Не разрешено запускать службу Намерение

Мое приложение прослушивает в фоновом режиме любое обновление местоположения и периодически отправляет эти захваченные местоположения на сервер. для этого я делаю:

in AndroidManifest.xml

  <receiver android:name="com.myapp.StartServiceBroadcastReceiver">  
    <intent-filter>  
      <action android:name="android.intent.action.BOOT_COMPLETED" />  
    </intent-filter>  
  </receiver> 

в StartServiceBroadcastReceiver я делаю:

  @Override
  public void onReceive(Context context, Intent intent) {

    try {

        /* start the location service */  
        Intent startServiceIntent = new Intent(context, LocationService.class);
        context.startService(startServiceIntent);

    } catch (Throwable e){ Log.e(TAG, "Exception", e); }  

  }

и LocationService в основном делают:

public void onCreate() {

  mLocationServices.setListener(this);
  mLocationServices.startLocationUpdates(true, // startWithLastKnownLocation,

                                         150000, // interval => 2.5 min  // Set the desired interval for active location updates, in milliseconds.
                                                                         // The location client will actively try to obtain location updates for your
                                                                         // application at this interval, so it has a direct influence on the amount
                                                                         // of power used by your application. Choose your interval wisely.

                                         30000, // fastestInterval => 30 s  // Explicitly set the fastest interval for location updates, in milliseconds.
                                                                            // This controls the fastest rate at which your application will receive location updates, which might be faster than setInterval(long)
                                                                            // in some situations (for example, if other applications are triggering location updates).
                                                                            // This allows your application to passively acquire locations at a rate faster than it actively acquires locations, saving power.

                                         900000, // maxWaitTime => 15 min  // Sets the maximum wait time in milliseconds for location updates.
                                                                           // If you pass a value at least 2x larger than the interval specified with setInterval(long), then location
                                                                           // delivery may be delayed and multiple locations can be delivered at once. Locations are determined at
                                                                           // the setInterval(long) rate, but can be delivered in batch after the interval you set in this method.
                                                                           // This can consume less battery and give more accurate locations, depending on the device's hardware
                                                                           // capabilities. You should set this value to be as large as possible for your needs if you don't
                                                                           // need immediate location delivery.

                                         LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY, // priority => Block level accuracy is considered to be about 100 meter accuracy.
                                                                                           //             Using a coarse accuracy such as this often consumes less power.

                                         25); // smallestDisplacement => 25 meters // Set the minimum displacement between location updates in meters  


}

@Override
public void onLocationChanged(Location location) {
   ....
}

Все работало хорошо на pre-oreo, но теперь не работает на oreo+. Что я могу сделать, чтобы моя служба работала?


comment
Вы пробовали startForegroundService()   -  person AskNilesh    schedule 24.09.2018
comment
использование службы переднего плана является одним из решений   -  person Manohar    schedule 24.09.2018
comment
@NileshRathod, в чем именно разница между startForegroundService и startService?   -  person zeus    schedule 24.09.2018
comment
@Redman тот же вопрос, что означает использование службы переднего плана?   -  person zeus    schedule 24.09.2018
comment
Возможный дубликат: stackoverflow.com/questions/46445265/   -  person Markus Penguin    schedule 24.09.2018
comment
Возможный дубликат Android 8.0: java. lang.IllegalStateException: Не разрешено запускать сервис Intent   -  person Markus Penguin    schedule 24.09.2018
comment
@MarkusPenguin: я обновляю вопрос, чтобы больше сосредоточиться на обновлении местоположения, чтобы он больше не был дубликатом.   -  person zeus    schedule 24.09.2018


Ответы (1)


Начиная с Android Oreo, вы не можете просто запустить фоновую службу, пока приложение находится в фоновом режиме.

Вы можете запустить свою службу в качестве службы переднего плана (Kotlin, но аналогично в Java):

val serviceIntent = Intent(context, LocationService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    context.startForegroundService(serviceIntent)
} else {
    context.startService(serviceIntent)
}

В вашей службе убедитесь, что вы вызываете startForeground как можно скорее. Это также выдаст уведомление, чтобы пользователь знал, что ваше приложение активно в фоновом режиме.

Как Анис БЕН НСИР указал в комментариях, на вас, вероятно, также повлияет новые ограничения фонового местоположения.

Существует хорошая статья о Ограничения фонового выполнения Oreo.

person Markus Penguin    schedule 24.09.2018
comment
Спасибо, Маркус, но что на самом деле означает запуск службы на переднем плане? в чем разница между фоновой службой? - person zeus; 24.09.2018
comment
@loki, в основном это означает, что сервис заметен пользователю (он показывает уведомление) и ему разрешено работать, даже если пользователь не использует приложение активно. См. также эту сводку. - person Markus Penguin; 24.09.2018
comment
@MarkusPenguin .. нет, невозможно постоянно показывать уведомление пользователю :( есть ли другой способ? - person zeus; 24.09.2018
comment
@loki Начиная с Android Oreo это необходимо сделать. Вы не сможете постоянно работать в фоновом режиме без ведома пользователя. Если вы не хотите получать постоянное уведомление, вы можете запланировать задание, но это конечно, зависит от вашего варианта использования. - person Markus Penguin; 24.09.2018
comment
@MarkusPenguin - Таким образом, как другое приложение получает обновление местоположения? ни у кого из них нет постоянного уведомления, как я вижу... - person zeus; 24.09.2018