0

I'm trying to build up a service which requests the device location every minute.

I need this to work in the background even when the application is closed. So far I managed to make it work on devices which have a pre-Oreo android OS but now I'm testing the service on android Oreo device and is not working when I close or put the application in background.

In my research I found that for Oreo devices, a Foreground Service with an ongoing notification should be used to achieve this so to start with I've implemented a simple Foreground Service like the below which shows an ongoing notification while the app is started and is removed when the app is stopped.

public class MyForegroundService extends Service {

    private static String TAG = MyForegroundService.class.getSimpleName();

    private static final String CHANNEL_ID = "channel_01";
    private static final int NOTIFICATION_ID = 12345678;

    private NotificationManager mNotificationManager;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    public MyForegroundService() {
        super();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");

        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        // Android O requires a Notification Channel.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = getString(R.string.app_name);

            // Create the channel for the notification
            NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT);

            // Set the Notification Channel for the Notification Manager.
            mNotificationManager.createNotificationChannel(mChannel);
        }

        startForeground(NOTIFICATION_ID, getNotification());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");

        stopForeground(true);
    }

    private Notification getNotification() {

        // Get the application name from the Settings
        String appName = PrefApp.getSettings(getApplicationContext()).getAppConfigs().getAppName();
        String applicationKey = PrefApp.getSettings(getApplicationContext()).getAppConfigs().getAppKey();

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setContentTitle(appName)
                .setContentText("Services are running")
                .setOngoing(true)
                .setPriority(Notification.PRIORITY_HIGH)
                .setSmallIcon(R.mipmap.ic_notification)
                .setWhen(System.currentTimeMillis());

        // Set the Channel ID for Android O.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId(CHANNEL_ID); // Channel ID
        }

        return builder.build();
    }
}

I am starting and stopping the above service using the below functions.

public void startMyForegroundService() {
    Log.d(TAG, "Start Foreground Service");

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(new Intent(getApplicationContext(), MyForegroundService.class));
    } else {
        startService(new Intent(getApplicationContext(), MyForegroundService.class));
    }
}

public void stopMyForegroundService() {
    Log.d(TAG, "Stop Foreground Service");
    stopService(new Intent(getApplicationContext(), MyForegroundService.class));
}

I'm testing the above service and for some reason the service gets killed after about 30 mins from when I start it. Can anyone tell me if I'm doing something wrong or possibly guide me for a solution which can work for me?

Note: I've followed this tutorial and tested their application as well and that it still not working. The service is being killed after some time.

Basically my goal is to implement a service which can run in the background (even when the application is closed) and get location updates every minutes.

Michele La Ferla
  • 6,775
  • 11
  • 53
  • 79
  • Does it only get killed if you're _not using the device_ for 30 minutes? Could be [Doze](https://developer.android.com/training/monitoring-device-state/doze-standby) interfering with your service, and causing an unexpected crash. Is there a relevant logcat from the time of the app death? – greeble31 Oct 10 '18 at 03:45
  • The device would be plugged in and as according to what I read in the documentation if the device is charging it shouldn't go in Doze mode. Besides that I am constantly monitoring it so I'm using the device. Unfortunately when the service gets killed the logcat gets cleared automatically so I cannot see any logs. – Tonio Galea Oct 10 '18 at 06:36
  • "...the logcat gets cleared automatically..." I would solve this problem first. logcat is there to help you understand what has happened, not to destroy information when you need it most. Consider adjusting the filters on the Android Studio logcat pane so that you can see all logs. – greeble31 Oct 10 '18 at 13:55

1 Answers1

0

You can use firebase job dispatcher for background service.

Code: Add this dependencies:

implementation 'com.firebase:firebase-jobdispatcher:0.8.5'

public class MyJobService extends JobService
{
    private static final String TAG = MyJobService.class.getSimpleName();

    @Override
    public boolean onStartJob(JobParameters job)
    {
        Log.e(TAG, "onStartJob: my job service class is called.");
        // enter the task you want to perform.
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters job)
    {
        return false;
    }
}

Create a job in the activity, you do it the way you used to do for background services.

/**
 * 2018 September 27 - Thursday - 06:36 PM
 * create job method
 *
 * this method will create job
**/
private static Job createJob(FirebaseJobDispatcher dispatcher)
{
    return dispatcher.newJobBuilder()
            //persist the task across boots
            .setLifetime(Lifetime.FOREVER)
            //.setLifetime(Lifetime.UNTIL_NEXT_BOOT)
            //call this service when the criteria are met.
            .setService(MyJobService.class)
            //unique id of the task
            .setTag("TAGOFTHEJOB")
            //don't overwrite an existing job with the same tag
            .setReplaceCurrent(false)
            // We are mentioning that the job is periodic.
            .setRecurring(true)
            // Run every 30 min from now. You can modify it to your use.
            .setTrigger(Trigger.executionWindow(1800, 1800))
            // retry with exponential backoff
            .setRetryStrategy(RetryStrategy.DEFAULT_LINEAR)
            //.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
            //Run this job only when the network is available.
            .setConstraints(Constraint.ON_ANY_NETWORK)
            .build();
}

/**
 * 2018 September 27 - Thursday - 06:42 PM
 * cancel job method
 *
 * this method will cancel the job USE THIS WHEN YOU DON'T WANT TO USE THE SERVICE ANYMORE.
**/
private void cancelJob(Context context)
{
    FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
    //Cancel all the jobs for this package
    dispatcher.cancelAll();
    // Cancel the job for this tag
    dispatcher.cancel("TAGOFTHEJOB");
}
Amit Jangid
  • 2,741
  • 1
  • 22
  • 28