Я хочу запустить Foreground Service вне зависимости от того, открыто или закрыто приложение, скажем, на 10 секунд. По прошествии этих 10 секунд Foreground Service должен быть уничтожен и вызван снова через 5 минут. Имеющийся у меня Foreground Service находит местоположение пользователя и затем сохраняет его в базе данных SQLite. По сути, я хочу сохранять новые координаты один раз каждые 5 минут, чтобы уменьшить расход заряда батареи.

Мой класс обслуживания:

public class LocationService extends Service{

private final static int UPDATE_TIME = 10000;
private final static int UPDATE_DISTANCE = 0;

private LocationListener locationListener;
private LocationManager locationManager;

private PowerManager.WakeLock mWakeLock;

private String latitude, longitude;

private DatabaseHelper myDb;

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

    myDb = new DatabaseHelper(this);
    locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);

    createWakeLock(); //Creates a wakelock
    createNotification(); //Creates a notification if SDK version is > 26

}

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

    mWakeLock.acquire(10*60*500L /*5 minutes*/);

    locationListener = new LocationListener() {

        @Override
        public void onLocationChanged(Location location) {

            Log.d("Location", "Updated");

            getCoordinates(location); //Gets coordinates
            insertCoordinates(latitude, longitude); //Sends coordinates to SQLite database
            sendDataToMainActivity(latitude, longitude); //Sends coordinates to MainActivity

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

        @Override
        public void onProviderEnabled(String provider) {

        }

        @Override
        public void onProviderDisabled(String provider) {

            Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(i);

        }

    };

    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, UPDATE_TIME, UPDATE_DISTANCE, locationListener);

    return START_NOT_STICKY;

}

@Override
public void onDestroy() {

    super.onDestroy();

    Log.d("Service", "Destroyed");

    if(locationManager != null)
        locationManager.removeUpdates(locationListener);

    mWakeLock.release();

}

private void createWakeLock() {

    PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);

    if(pm != null)
        mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "myApp:myWakeLock");

}

private void createNotification() {

    Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this,0, notificationIntent, 0);

    Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Service")
            .setContentText("Coordinates Location Running")
            .setContentIntent(pendingIntent)
            .build();

    startForeground(1, notification);

}

private void getCoordinates(Location location) {

    this.latitude = String.valueOf(location.getLatitude());
    this.longitude = String.valueOf(location.getLongitude());

}

private void insertCoordinates(String latitude, String longitude) {

    boolean inserted = myDb.insertData(latitude, longitude); //Insert coordinates

    //Check if insertion is completed
    if(inserted)
        Toast.makeText(LocationService.this, "Coordinates Inserted", Toast.LENGTH_SHORT).show();
    else
        Toast.makeText(LocationService.this, "Coordinates Not Inserted", Toast.LENGTH_SHORT).show();

}

private void sendDataToMainActivity(String latitude, String longitude) {

    Intent i = new Intent("location_update");
    i.putExtra("latitude", latitude);
    i.putExtra("longitude",longitude);

    sendBroadcast(i);

}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}
1
Iraklis Eleftheriadis 11 Ноя 2019 в 11:09

3 ответа

Используйте Fused Location Api для запроса обновлений местоположения, которые вызовут ожидающее намерение (скажем, запускает службу намерения) в указанном интервале повтора (дайте 5 минут). Таким образом, Fused Location Api считывает местоположение каждые 5 минут и отправляет его в намерение сервис, откуда вы можете выполнять свою обработку.

См. Ссылку this, чтобы получить более подробную информацию.

1
Jinesh Francis 11 Ноя 2019 в 11:27

Вы можете использовать диспетчер сигналов тревоги, чтобы установить точный сигнал тревоги, запустить службу в функции сигнала при получении, запустить службу переднего плана в течение 5 минут, а затем установить следующий сигнал тревоги.

0
Eren Tüfekçi 11 Ноя 2019 в 11:49

«Fused Location Api» может не работать в фоновом режиме из-за ограничений управления питанием. Вам следует использовать Alarm Manager, но в последней версии Android есть некоторые ограничения. версии. Подробнее о DOZE здесь

    AlarmManager alarm =
            (AlarmManager)getSystemService(Context.ALARM_SERVICE);
    if (alarm == null) return;  // for instant apps

    Intent intent = new Intent(this, MyBroadcastReceiver.class)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerInMillis,
                PendingIntent.getBroadcast(this, intent, PendingIntent.FLAG_UPDATE_CURRENT));

    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        AlarmManager.AlarmClockInfo ac=
                new AlarmManager.AlarmClockInfo(triggerInMillis, null);
        alarm.setAlarmClock(ac, PendingIntent.getBroadcast(this, intent, PendingIntent.FLAG_UPDATE_CURRENT));

    } else {
        alarm.setExact(AlarmManager.RTC_WAKEUP, triggerInMillis,
                PendingIntent.getBroadcast(this, intent, PendingIntent.FLAG_UPDATE_CURRENT));
    }
0
Denis Korotenko 12 Ноя 2019 в 10:43
Что означает контекст? Я получаю сообщение об ошибке, когда набираю AlarmManager alarm = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);, но когда я меняю его на AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);, он работает. Я не уверен, какую переменную поместить в контекст. Обратите внимание, что у меня нет класса BroadcastReceiver, у меня есть только Service Class, который я включил в свой вопрос выше.
 – 
Iraklis Eleftheriadis
12 Ноя 2019 в 09:36
Context означает любой экземпляр класса Context (Activity, Service, Application - все они расширяют Context). Вы должны объявить свой MyBroadcastReceiver как отдельный файл. Открытый класс MyBroadcastReceiver расширяет BaseBroadcastReceiver и добавляет в AndroidManifest Пример BroadcastReceiver
 – 
Denis Korotenko
12 Ноя 2019 в 10:41
И ваш MyBroadcastReceiver запустит вашу службу в методе onReceive
 – 
Denis Korotenko
12 Ноя 2019 в 10:54
Я создал класс MyBroadcastReceiver и по методу onReceive написал это Intent serviceIntent = new Intent(context, LocationService.class); ContextCompat.startForegroundService(context, serviceIntent);
 – 
Iraklis Eleftheriadis
12 Ноя 2019 в 14:33
Итак, я заставил AlarmManager работать. Однако я хочу, чтобы Service был уничтожен после того, как я вставлю координаты в свою базу данных SQLite. В настоящее время служба работает бессрочно. По сути, я хочу, чтобы мой AlarmManager запускал мой Service примерно на 10 секунд, чтобы выполнить все задачи, уничтожить его и снова вызвать его через 5 минут.
 – 
Iraklis Eleftheriadis
12 Ноя 2019 в 16:41