Я создаю код для непрерывного отслеживания местоположения на устройствах Android, который должен продолжать работать, даже когда телефон заблокирован. Я реализовал сервис переднего плана для этого, основываясь на примерах Google. Несмотря на то, что он продолжает работать, когда телефон заблокирован, я заметил значительно более длительные интервалы между обратными вызовами и регистрацией местоположения, которые, кажется, происходят, когда телефон заблокирован с выключенным экраном. Есть ли какой-то способ предотвратить это / я все еще что-то упускаю, чтобы предотвратить включение фоновых сервисных ограничений?
Мой код в настоящее время запускается как привязанный сервис из приложения, затем он преобразуется в фоновый сервис, как только приложение заказывает его для отслеживания местоположения. Как только приложение выходит на передний план, служба перестает быть привязанной и превращается в службу переднего плана. Все мои тесты проводились на Nokia 2.1 под управлением Android 9 Go Edition.
Для запроса местоположения я настраиваюсь с интервалом в 1 минуту и максимальным временем ожидания 5 минут. Однако в заблокированном состоянии я заметил, что между точками задержка достигает целых 20 минут.
Я пробовал с более жесткими границами с интервалом 10 секунд, максимальное время ожидания 1 минута. Похоже, что между исправлениями местоположения производительность по-прежнему падает до порядка 60-80 секунд, хотя, похоже, это происходит реже.
(Я думаю) важные части службы определения местоположения ниже. Если требуется больше деталей, просто спросите, код не является секретным.
//Snip: preamble
public class LocationTracker extends Service {
private final String TAG = LocationTracker.class.getSimpleName();
private final String NOTIFICATION_CHANNEL = "LocationTrackerChannel";
private int NOTIFICATION_ID = 12345678;
private FusedLocationProviderClient locationClient;
private LocationRequest locationRequest;
private Looper eventLooper;
private Boolean running = false;
// Snip: processing related definitions/variables
public class LocalBinder extends Binder {
LocationTracker getService() {
return LocationTracker.this;
}
}
private IBinder binder = new LocalBinder();
LocationCallback locationResultHandler = new LocationCallback() {
@Override
public void onLocationResult(LocationResult result) {
super.onLocationResult(result);
Log.i(TAG,"New location: " + result.getLastLocation() + " " + result.getLocations().size());
for (Location loc : result.getLocations()) {
// Snip: process results
}
if (unsent >= 5) {
// send result over network
}
}
};
public LocationTracker() {
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate!");
locationClient = LocationServices.getFusedLocationProviderClient(this);
HandlerThread eventHandlerThread = new HandlerThread(TAG);
eventHandlerThread.start();
eventLooper = eventHandlerThread.getLooper();
locationRequest = new LocationRequest();
locationRequest.setInterval(60*1000);
locationRequest.setMaxWaitTime(5*60*1000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL,
getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
@Override
public IBinder onBind(Intent intent) {
stopForeground(true);
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
if (running)
startForeground(NOTIFICATION_ID, BuildNotification());
return true;
}
@Override
public void onRebind(Intent intent) {
stopForeground(true);
super.onRebind(intent);
}
public boolean startLocationTracking(double latOffset, double lonOffset, long timeOffset, String host, int port) {
Log.i(TAG, "Starting tracking");
if (running) stopLocationTracking();
try {
// Snip: setup processing parameters
// Setup actual geolocation updates
locationClient.requestLocationUpdates(locationRequest, locationResultHandler, eventLooper);
// Setup service to run in background
startService(new Intent(getApplicationContext(), LocationTracker.class));
running = true;
return true;
} catch (SecurityException unlikely) {
Log.w(TAG, unlikely.toString());
locationTransmitter = null;
return false; // report failure
}
}
public void stopLocationTracking() {
Log.i(TAG, "Stopping tracking");
if (!running) return;
try {
locationClient.removeLocationUpdates(locationResultHandler);
} catch (SecurityException unlikely) {
//ignore
}
stopSelf();
locationTransmitter = null;
running = false;
}
private Notification BuildNotification() {
PendingIntent openAppIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentIntent(openAppIntent)
.setContentTitle("WALKINTRACKER")
.setContentText("Recording location")
.setSmallIcon(R.drawable.common_full_open_on_phone)
.setTicker("Recording location")
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setChannelId(NOTIFICATION_CHANNEL);
return builder.build();
}
}