4

I have implemented some background task with WorkManager and with usage this Guide. One time I needed to use CoroutineWorker. I find these guide pretty good but every time I need new requirement for background processing I start new research for what I need. So my question is what is the correct way to address the following use cases with modern Android. Also please consider that different phone brands kill background task defiantly (Some brands more harsh on background processing). And when do I need to use persistent notification and when it is not required, and when to use AlarmManger. Please write for each the best way to implement and if Persistent notification required.

Use cases:

1. Downloading large file (500mb)

a. Once a day on exact time

b Once a day when the OS can, in any time

2. Downloading small file (5k)

a. Once a day on exact time

b Once a day when the OS can, in any time

3. Setting alarm at exact time

4. Sync DB with server (large data about 5min runtime)

a. Every 15 min (Minimal time?)

b. Once a Day

5. Sync DB with server (small data less than 1sec runtime)

a. Every 5 min

b. Every 15 min

c. Once a Day

Dim
  • 4,527
  • 15
  • 80
  • 139

2 Answers2

3

According to this reference of WorkManager, there are three types of persistent work you can schedule through it,

  • Immediate: Tasks that must begin immediately and complete soon. May be expedited.
  • Long Running: Tasks which might run for longer, potentially longer than 10 minutes.
  • Deferrable: Scheduled tasks that start at a later time and can run periodically.

This means most of your use cases are achievable by using WorkManager except two cases where you require it to run "Every 5 min" & "Setting alarm at exact time".

It is recommended from here that if you want to set alarm at exact time then WorkManager shouldn’t be used, instead use AlarmManager which will wake device even from doze mode at specified time.


Checkout all possible executions that work manager provides: WorkManager flow (Courtesy of WorkManager guide)

Hence, following are all possible approach you can use according to your use-cases:

  1. Downloading large file (500mb)

    a. Once a day on exact time

    Answer: You can use PeriodicWork here scheduled for every 24 hours from given start time, since it's long running operation you can make it expedited/foreground to track ongoing progress. Although bear in mind that downloading requires active internet connection and at specified interval if it's not available then it will be scheduled for delayed/later execution.

    PeriodicWorkRequestBuilder<LongRunningWorker>(1, TimeUnit.DAYS)
        .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
        // Additional configuration
        .build()
    
    //Calling setForeground() from doWork() will show ongoing notification
    

    b. Once a day when the OS can, in any time

    Answer: This is the best example where you can execute some task indeterminately using PeriodicWork. Here you can make it deferrable since it's not required to be executed at specific time.

    PeriodicWorkRequestBuilder<LongRunningWorker>(1, TimeUnit.DAYS)
         // Additional configuration
         .build()
    
    //Calling setForeground() from doWork() will show ongoing notification
    
  2. Downloading small file (5k)

    a. Once a day on exact time

    Answer: It can be PeriodicWork with immediate execution (expedited work) scheduled for 24 hours, since it won't take long to download small file.

    PeriodicWorkRequestBuilder<ShortSpanWorker>(1, TimeUnit.DAYS)
        .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
        // Additional configuration
        .build()
    

    b. Once a day when the OS can, in any time

    Answer: It can be PeriodicWork with deferrable execution that can be scheduled at 24 hours.

    PeriodicWorkRequestBuilder<ShortSpanWorker>(1, TimeUnit.DAYS)
       // Additional configuration
       .build()
    
  3. Setting alarm at exact time

    Answer: For setting alarm to be executed on exact time, you should use AlarmManager. This usecase is not possible with WorkManager because, it doesn't interrupt Doze mode (Device's deep sleep).

  4. Sync DB with server (large data about 5min runtime)

    a. Every 15 min (Minimal time?)

    Answer: This can be PeriodicWork scheduled every 15 mins being foreground work since it is long running.

     PeriodicWorkRequestBuilder<SyncToServerWorker>(15, TimeUnit.MINUTES)
         // Additional configuration
         .build()
    
     //Calling setForeground() from doWork() will show ongoing notification
    

    b. Once a Day

    Answer: This can be PeriodicWork scheduled every 24 hours being foreground work since it is long running.

     PeriodicWorkRequestBuilder<SyncToServerWorker>(1, TimeUnit.DAYS)
         // Additional configuration
         .build()
    
     //Calling setForeground() from doWork() will show ongoing notification
    
  5. Sync DB with server (small data less than 1sec runtime)

    a. Every 5 min

    Answer: This use-case is not achievable since minimum time-frame for WorkManager's periodic work is 15 mins. Hence, it is suggested to manage this periodic work manually by foreground service/alarm manager combination.

    b. Every 15 min

    Answer: This is achievable by PeriodicWork scheduled for every 15 mins which can either expedited or deferrable based on how urgent/relaxed it is required.

     PeriodicWorkRequestBuilder<SyncDataWorker>(15, TimeUnit.MINUTES)
         .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) // Decide whether to make it expedited or deferrable here conditionally
         // Additional configuration
         .build()
    

    c. Once a Day

    Answer: This is example of PeriodicWork scheduled for every 24 hours which can either expedited or deferrable based on how urgent/relaxed it is required.

     PeriodicWorkRequestBuilder<SyncDataWorker>(1, TimeUnit.DAYS)
         .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) // Decide whether to make it expedited or deferrable here conditionally
         // Additional configuration
         .build()
    

Reference for creating long running workers: https://developer.android.com/topic/libraries/architecture/workmanager/advanced/long-running#long-running

Hope this helps!

Jeel Vankhede
  • 11,592
  • 2
  • 28
  • 58
2

Please check the answer I gave here for more information:

Android recommended and reliable API for periodic background work?

1. Downloading a large file (500mb)

a. Once a day on exact time - you can set an alarm here to be exact, but then you hit the Android 12 limitation for starting services from the Background(more on this in the other comment). So it depends on the use case. I just would not go there.

b Once a day when the OS can, in any time - go with the WorkManager, but in theory it depends on the Power Buckets so if you go in the lower ones you might go a little above a day. Also, it is different to start and to finish. You might start hitting the 10min per day limitation. (more on this in the other comment)

2. Downloading small file (5k) a. Once a day on exact time - as a large file.

b Once a day when the OS can, in any time - as a large file.

3. Setting alarm at exact time - it depends on what you do. I don't understand this

4. Sync DB with server (large data about 5min runtime) - you need WorkManager for stuff like this.

For all the above - the 15min comes from Doze mode. But even it comes in "2 flavors". This 15min is just on theory. In reality it might be even more. WorkManager has the concept of a "periodic work". In reality there is no such a thing. WorkManager uses the concept of constraints. So you have the constraint that you need a Network, you are constrained that you need a device to be charging and you have a "time constrain". So you see - a "periodic work" of 24 hours is just a work with an extra constrain: "do not start in less than 24 hours". But it doesn't mean "every 24 hours". In theory 24 might have passed, the timing constrain is satisfied and then for other reason you are executed successfully in 1 week and the work is rescheduled again with another 24 hours time constrain.

For stuff like "every 5min, 15min, 15min" - just raise a Service with the following text in the Service notification: "Our application hates your battery", never stop it, and do whatever you need :) But is totally against the new Android concept.

Even if you use push notifications if they are not a high priority you will effectively fall back to WorkManager to do the work later.

Even like I said: "once a day" means "most likely once a day"

a. Every 15 min (Minimal time?)

b. Once a Day

5. Sync DB with server (small data less than 1sec runtime)

a. Every 5 min

b. Every 15 min

c. Once a Day

Yavor Mitev
  • 1,363
  • 1
  • 10
  • 22
  • Man nice answer, but what about similar thing with foreground service working all the time? – KyluAce May 30 '22 at 12:27
  • If it is for uploading files - it is "going against the system". But no one can stop you to do so. But nowadays the Services are in cases where.. let's say you have "an active interaction with the user." You need to actively track the user - for example a running app, or google maps, or a music player, etc. Or also it is used in antivirus apps. Where it is really crucial to be alive at all times. I think now to problem comes from the PMs. They don't understand how Android works and they try to sell features that are just not good for the user itself. We need to reeducate the users. @KyluAce – Yavor Mitev May 31 '22 at 07:34
  • WorkManager gives you the concept - "it will finish for sure". AlarmManager - you know in advance when you need it, but you need to be exact Push Notifications - you do not know when and you depend on an external source. And with Push Notifications, you can branch again: "do it now" or fall back to the WM and do it for sure sometime in the future. – Yavor Mitev May 31 '22 at 07:37
  • I'm creating an app that all the time need to scan for beacons. But It have to scan it all the time without interruptions etc. It's quite a problem because first of all if I create background service it won't work (limitations) so we need to create foreground service, but it's still not enough because all phone manufactures also has something like battery optimisations (which can cause some interrupts) + some phone manufactures has problem with killing apps in backgrounds. And I'm still fighting to work it stable. – KyluAce May 31 '22 at 08:18
  • @KyluAce hard taks. You can't make it work everywhere. But like I said in the other comment - ask the user to exempt you from battery optimization. Also you can make some hacks like Viber - show an notification from time to time so the user can click it and open the app so you are back in the foreground. Also you should check the www.dontkillmyapp.com page. There is a lot of info there. But it is a "war" with the OS :) – Yavor Mitev May 31 '22 at 09:22