Извините, это длинный вопрос, но я надеюсь, что один из вас, экспертов, сможет помочь новичку, который просто сходит с ума !!
У меня есть приложение для Android, которое использует фоновый сервис для получения исправлений GPS (с использованием Google Play Services) каждые 20 секунд. Он сравнивает широту и долготу с теми, что в списке, и, если он находит совпадение, он отправляет широковещательную рассылку получателю, который запускает действие на переднем плане, чтобы предупредить пользователя.
Я использую фоновую службу, потому что между оповещениями пользователей обычно от 2 до 20 минут, а между ними нет взаимодействия с пользователем. Приложение использует действие переднего плана для пользователя, чтобы выбрать нужные ему опции, но затем закрывает все действия переднего плана, оставляя запущенным только действие фона.
Это хорошо работало на Android 4.3, на моем старом устройстве, но я сейчас обновляю его на Android 8 (Oreo) (тестирую на Sony Xperia XZ1Compact). Я добавил
<uses-permission
android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/
в манифест, и это заставило приложение запрашивать разрешение при первом запуске. В настройках моего устройства приложение отображается как разрешенное исключение энергосбережения.
Код для фонового сервиса (извините, его довольно много, но я включил его на случай, если он уместен!):
package com.barney.trackgps;
import android.Manifest;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class ApiTrackService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
GoogleApiClient mLocationClient;
LocationRequest mLocationRequest = new LocationRequest();
public static final String ACTION_LOCATION_BROADCAST =
ApiTrackService.class.getName() + "LocationBroadcast";
public static final String EXTRA_LATITUDE = "extra_latitude";
public static final String EXTRA_LONGITUDE = "extra_longitude";
int interval=20; //time between fixes in seconds
@Override
public void onDestroy(){
super.onDestroy();
stopSelf();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("sTag","Got to apitrack");
mLocationClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationRequest.setInterval(interval*1000);
mLocationRequest.setFastestInterval(1000);
int priority = LocationRequest.PRIORITY_HIGH_ACCURACY;
mLocationRequest.setPriority(priority);
mLocationClient.connect();
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onConnected(Bundle dataBundle) {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient,
mLocationRequest, this);
}
@Override
public void onConnectionSuspended(int i) {
}
//to get the location change
@Override
public void onLocationChanged(Location location) {
boolean locFound=false;
Log.v("sTag","Got a fix");
/*does stuff to compare latitude and longitude with places in a list
and sets locFound=true if it finds a match*/
if (location != null) {
GPSLog=GPSLog+"Found";
if (locFound) {
Log.v("sTag", "Sending broadcast");
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setAction("com.AboutMyJourney.posBroadcast");
sendBroadcast(intent);
}
}
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
//Log.d(TAG, "Failed to connect to Google API");
}
}
Приложение работает нормально, если одно из его основных заданий открыто и доступно. Отслеживание с использованием logcat показывает, что фоновая служба получает исправления GPS и код в onLocationChanged (см. Код выше) запускается каждые 20 секунд.
Приложение по-прежнему работает нормально, и метод onLocationChanged по-прежнему запускается каждые 20 секунд, если я разрешаю моему приложению закрыть все его действия на переднем плане и запускать только фоновую службу, указанную выше, при условии, что другое (совершенно не связанное) приложение, которое Звонки для местоположений GPS открыты и видны.
Если, однако, у меня нет приложения, которое использует GPS, видимый на экране, то отслеживание GPS прекращается; Метод onLocationChanged больше не запускается, и я больше не получаю исправления GPS.
Если я затем открою одно из основных заданий моего приложения, GPS-отслеживание снова запустится, показывая, что фоновая служба не была убита.
Я предполагаю, что это как-то связано с изменениями, которые были сделаны для реализации режима энергосбережения / режима ожидания, и я просто не понимаю его правильно. Тем не менее, все советы, которые я могу найти, указывают на то, что фоновая служба будет работать до тех пор, пока она разрешена как исключение в белом списке устройства, но этого явно не происходит.
Я бы предпочел, чтобы фоновая служба работала, так как это означает наименьшее количество работы для написания нового кода !. Однако в некоторых ответах на подобные вопросы предлагается использовать службу переднего плана с уведомлением. Будет ли это соответствовать моему требованию, чтобы пользовательский интерфейс не был виден (за исключением, может быть, для уведомления) большую часть времени, только побуждая пользователя делать что-то каждые несколько минут, но оставляя его или ее свободным делать другие вещи в то же время? Будет ли это нормально работать и в старых версиях Android?
Может кто-нибудь, кто понимает это лучше, чем я (вероятно, нетрудно понять это лучше, чем я!), Помогите, пожалуйста?