1

So, I am trying to run a service in the background that can send some app data to my server So far I've tried using AlarmManager, JobScheduler classes to run the service periodically but its no use since any alarms created and jobs scheduled ARE CLEARED as the application is closed (closed here does not mean force stopped). I looked around and have seen a lot of StackOverflow questions for similar usecases(but older android versions) and same clearing problem, but no concrete answer or implementation i found is working. (is this an issue with latest versions of android?)

My use case is small data(in/ kbs) upload once or twice a day from the application to maintain usage track of the application.

Since i can't expect user to keep his app open all day...

  • How to achieve this periodicity as explained ?


UPDATE-1

According to @Kabumere answer and some help from android dev docs i used WorkManager and tried this code below
Expected behaviour(for now)
continous repeating logs with 20 min interval (20 min is just for testing) regardless if app was closed(ie that 30 min interval between 6 and 7)
Actual Behaviour

  1. app is in focus on testing device(genymotion android 9)
  2. 08:47 onCreate schedules first job and it runs
  3. app is closed but present in recents
  4. 09:02 second job runs (15 min apart)
  5. app now closed from recent
  6. // no further logs for 30 mins, jobs not started
  7. 09:36 application started manually, nothing is enqueued as per logic
  8. jobs continue at 15 min interval
2020-08-05 08:47:53.260 7746-7746/com.example.workmanagerapi D/debugTag: Scheduling
2020-08-05 08:47:53.655 7746-7802/com.example.workmanagerapi D/debugTag: DOING SOME WORK !!!
2020-08-05 09:02:53.732 7746-8007/com.example.workmanagerapi D/debugTag: DOING SOME WORK !!!
2020-08-05 09:36:47.165 8347-8347/com.example.workmanagerapi D/debugTag: Already Scheduled
2020-08-05 09:36:47.193 8347-8376/com.example.workmanagerapi D/debugTag: DOING SOME WORK !!!
2020-08-05 09:51:47.269 8347-8486/com.example.workmanagerapi D/debugTag: DOING SOME WORK !!!

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SharedPreferences SP = getSharedPreferences("prefs",MODE_PRIVATE);
        SharedPreferences.Editor editor = SP.edit();
        boolean enqueue = SP.getBoolean("enqueue", false);
        if(enqueue) {
            Log.d("debugTag", "Already Scheduled");
        }
        else {
            Log.d("debugTag", "Scheduling");
            doWork();
            editor.putBoolean("enqueue",true);
            editor.apply();
        }
    }

    private void doWork() {
        PeriodicWorkRequest.Builder myWorkBuilder = new PeriodicWorkRequest.Builder(MyWorker.class, 1, TimeUnit.MINUTES);
        // i read on docs that this time limit will default to (5+15) minutes minimum
        PeriodicWorkRequest myWork = myWorkBuilder.build();
        WorkManager.getInstance(this).enqueue(myWork);
    }
}

MyWorker.java

public class MyWorker extends Worker {
    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        Log.d("debugTag", "DOING SOME WORK !!!");
        return Result.success();
    }
Simian
  • 11
  • 2

1 Answers1

1

I'd recommend using the WorkManager API over creating a Service.

With WorkManager you can enqueue a PeriodicWorkRequest that will run at the interval you set in its Builder constructor (like run every 24 hours). Scheduled jobs through WorkManager should not be deleted when the app is closed, will be automatically rescheduled at different events like device reboot, and can run even when the app is in the background.

You can also set Constraints on WorkRequests so you can specify things like "only attempt to run this job if we have any sort of data connection" (setRequiredNetworkType(NetworkType.CONNECTED)). This is good for your use case of needing to send data, which will require some connection.

kabumere
  • 353
  • 2
  • 8
  • Hey, thanks for suggestion. I tried your approach, for testing whether it'll survive app closing i tested with the minimum interval it allowed and doesn't seem to work. Can you take a look at code, in case i did something wrong :) – Simian Aug 05 '20 at 04:41
  • Sure, let me see what you have. – kabumere Aug 05 '20 at 05:03
  • @Simian I don't have the reputation to post comments on your original post, so I'll post here: You're (likely) seeing expected behavior. Some devices treat removing the app from Recent Apps the same as force closing (see this answer and sources: https://stackoverflow.com/a/52605503/14032472). When force closed, your app's process is killed and nothing runs (including WorkManager jobs). From my experience however, most users are not manually clearing apps from the recent apps list. – kabumere Aug 05 '20 at 05:22
  • Furthermore, some FYIs: you can get rid of all that SharedPreferences logic by using `enqueueUniquePeriodicWork` instead of just `enqueue` on the WorkManager instance. This lets you pass `ExistingPeriodicWorkPolicy.KEEP`, which tells WorkManager to not enqueue the work again if it already exists. So you can call `doWork` as much as you want. Further, I see you included this as a comment already, but it's good practice to not set intervals under 15 minutes (right now WorkManager will silently change it to the default - 15 min, but this can change unexpectedly in the future though.) – kabumere Aug 05 '20 at 05:26
  • so is this periodicity even achievable, unless user actually opens app guaranteed once per day? given latest android versions mixed with OEM force closing issue (I was also thinking of using FCM somehow, but i wonder if that's also limited to notifs only and whether it can start services, _if it's not also affected by the same issue_) – Simian Aug 07 '20 at 05:38
  • It's impossible to guarantee your job will fire at the exact interval you set on new versions of Android in 2020, period. Between Doze, App Standby, OEM specific battery saving implementations (see [DontKillMyApp](https://dontkillmyapp.com/)) and a plethora of other variables, a developer can no longer guarantee their jobs will fire within the minute, hour or sometimes even the same day. The best you can hope for: 1) a user frequently interacts with their device each day, 2) never lets their battery level get too low and 3) has a device not listed as aggressive on DontKillMyApp. – kabumere Aug 07 '20 at 14:32