Background
Ever since Android O came out I had trouble with what classes and methods I should use when I want to schedule background sync tasks and notifications, more specifically, I want to do these two separate things:
Background sync task to download data from the server, and notify the user about important information (that was just fetched from the server). These syncs should occur at an almost precise time of the day (e.g. 21:30 ±10min).
Notify the user about an upcoming event, for example, one week before an exam.
Because Android O has placed some restrictions on AlarmManager, I cannot set a background service that runs at a specific time of the day, unless I use getForegroundService(), which, as the docs say, should only be used for services that are noticeable to the user.
What I tried / considered
I have been using JobService that runs periodically every so and so hours, but I would prefer for it to run at a more specific time of the day.
I have looked into CalendarProvider, and also considered a push notification service, but it seems to me like an overkill for simple tasks like these.
Question
My final question is what methods I could, or I should use to implement the above features?
Use WorkManager this is the best way to Run Task in Background in Android Oreo and Pie versions and it also works in older versions of Android.
See the Documentation
https://developer.android.com/topic/libraries/architecture/workmanager
https://developer.android.com/topic/libraries/architecture/workmanager/basics
https://developer.android.com/topic/libraries/architecture/workmanager/advanced
GitHub Example
https://github.com/krunalpatel3/WorkManager-Example-Andorid
Reference
http://thetechnocafe.com/how-to-use-workmanager-in-android/
https://www.youtube.com/watch?v=fAQKvBHeg_w
https://www.youtube.com/watch?v=1VVir3-4hII
https://www.youtube.com/watch?v=0jgkQYebYvQ
https://www.youtube.com/watch?v=ooP8kkhvRQI
Related
I would like to have a background job to run like 2-3 times a day, but even less it's ok. It's just a quick api call to my server, it doesn't need to update the UI, infact I prefer that it runs when the app is not in the foreground, but that's another topic.
I've read that latests versions of Android and iOS or even manifacturers restrict the app but I don't need these task to be at certain time precisely.
I'm not sure if I should use the JobScheduler or WorkManager for Android and the BackgroundFetch or BackgroundTask for iOS.
Let's say the task should run 3 times a day so every 8 hours roughly.
The thing is that a user might not open the app again so the task should be scheduled to be recurrent, maybe every time it runs it could schedule another one, but if one fails that line could never be reached.
I don't need to support old operating system version, only iOS 15+ and Android api 30+.
Thank you for the help!
Apple is strict about hardware resources occupied by App, not to mention App in the background state. When App enter the background state, it will soon be suspended by the OS, unless you apply for permission from OS. Only several modes could be allowed to run in the background, see the following picture
You want a background cron job which is not allowed in iOS.
For Andriod, you know we could use WorkManager or JobSchedule. Here are some documents that you could refer to:
Getting Started With WorkManager
Android Job Scheduler
Hope it works for you.
Hello flutter/mobile developers,
I have a particular problem at hand and I need some advice. I need to create an app that will do a certain task at specific times of the day. The times will change daily, and it will get the updated times via a REST call at midnight (or at off peak hours). The task must at the scheduled time no matter what, even after device restart, etc. I have looked into this extensively and I'm coming away with the feeling that Flutter does not handle a scheduled task well, especially in iOS which can terminate an app for whatever reason.
The options I have looked into are:
workmanager (https://pub.dev/packages/workmanager/changelog): This seems the most promising, if not for the minimum frequency of 15 minutes, which is not enough for me. I would need to check every minute if it is time to do the task. Is there a way around this limitation?
Native solution. I have very little-to-no experience with native iOS and Android coding so I would not prefer this solution. But through some research I have seen some examples where a task can be scheduled through this approach.
Server side notification. This seems like a good solution on the surface, and I need advice on this. The calculation whether it is time to run the task will happen server-side, and a notification (through Firebase, for example) can be sent to the device, which will trigger the task to be run. Is this even feasible, will the device actually run code when it gets the notification?
So these are my options. Which doe you think is the most doable? If someone with more mobile experience than me can help me out I would appreciate it, maybe there is a better solution that the three I have proposed. Thank you.
The times will change daily, and it will get the updated times via a REST call at midnight (or at off peak hours).
This smells like bad architecture. Why?
You are DDOS'ing your update server at midnight (if you have many users in the same timezone). You can stagger your HTTP requests by a few seconds to fix this, but this is a band-aid, not a long term solution.
because you are inverting the dependency: It sounds like timing is the responsibility of the server (hence your clients call it to ask for the latest time). Your clients should not be the ones asking the server for updates, because now your client has 2 jobs: Schedule the schedule updates and also schedule the scheduled task for the user. Making clients ask the server is the wrong direction. You should send messages from the server to update the schedule on the device.
Even if you do poll the server for schedule updates, you should make the mobile app schedule notifications/ alarm at the time you want. Using silent notifications is a known workaround the limitations of background scheduling on iOS. On Android, WorkManager is not the right library, you should use AlarmManager.
Here is how another StackOverflow thought about using local notifications to solve the problem: They used flutter_local_notifications
Answering the bullet points
On Android, don't use WorkManager, use AlarmManager instead, or even better, schedule notifications. Having said there are some manufacturer specific quirks on Android, see the flutter_local_notifications docs:
Consequently, scheduled notifications may not work when the application is in the background on certain devices (e.g. by Xiaomi, Huawei). If you experience problems like this then this would be the reason why. As it's a restriction imposed by the OS, this is not something that can be resolved by the plugin.
Its not necessary to use Native code, notifications is a standard feature.
You can keep the polling architecture for now since its simpler (but dirtier). Even if you would so the server side architecture, I would send messages from server to client to only update the client side schedule, not to trigger work/ user alerts, otherwise you are making your application dependent on the internet when it doesn't sound like the internet is required (unlike social media notifications). This would lead to bad user experience for badly connected devices.
You can send Data Notifications through Firebase, and handle them with the onBackgroundMessage callback. See here: https://firebase.flutter.dev/docs/messaging/usage#background-messages
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
print("Handling a background message: ${message.messageId}");
}
void main() {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyApp());
}
From the documentation (Android/Apple):
It must not be an anonymous function.
It must be a top-level function (e.g. not a class method which requires initialization).
I have some critical data to be synced with the server every half an hour or so. I tried using WorkManager but turns out that it cannot run reliably even if I have REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. So then I thought I should use AlarmManager, but they wrote in the docs:
This is a case where you might be tempted to use a repeating alarm. But if you own the server that is hosting your app's data, using Google Cloud Messaging (GCM) in conjunction with sync adapter is a better solution than AlarmManager.
So then I went to SyncAdapter docs and they mentioned with a star:
We recommended WorkManager as the recommended solution for most background processing use cases. Please reference the background processing guide to learn which solution works best for you.
I also read in quite a few blog posts that Sync Manager will be phased out or replaced in the near future.
So I am back again with WorkManager. Is it a good idea to use SyncAdapter in 2020?
If you need to have a sync reliably every 30 minutes, use Firebase Cloud Messaging (the evolution of GCM) and use WorkManager to enqueue a Worker that does the actual backup upload when the application on the device receives the message.
If your application is going to be always in the background you can expect that it will drift into having less and less execution time while in the background. Ignoring battery optimization helps in that case.
Here you have the information regarding the different power buckets.
Note This is for stock Android, some OEMs add additional battery optimization that further reduce background tasks. You can see a collection on issues on https://dontkillmyapp.com/
So, I wanted to use a Firebase Listener in the background because there's some code I need to trigger while the app is closed based on Database values. I thought I could just throw the listener on a Service, however reading the docs looks like Services are no longer a good option because of how the OS works in recent versions.
I found about the WorkManager class which supposedly is the best new option to implement background code and it looks fine and all however the 15 minutes minimum time for periodic jobs is way to much time for what I need.
So I was wondering what could be the best practice possible to use a Firebase Listener on the background? Or should I just abandon the idea of using a listener on the background at all?
You can't force a listener to stay live while the app has been backgrounded. This is because Android can (and will) kill the app process when the user isn't using it any more. Your connection to the database will be lost.
You could use WorkManager to wake your app periodically to check the database, but that doesn't sound like what you want.
The preferred solution is to use Firebase Cloud Messaging from a backend you control to ping the app when you know there is new data it's interested in.
I have been developing for Android for little less then 2 years, and I am still puzzled by this seemingly simple question.
When should one implement a service?
From my experience there are some rare cases but I am questioning this because on every phone there are quite a lot of them running and I doubt it's just a poor application design.
This is essentially core of my question but following are some of my experiences and thoughts about the subject which can explain my question in more detail.
In all apps that I have developed only one really required a service. It was a background sound recorder and I was using it as Foreground service with notification since I wanted buttons to be able to control it (like music players do for example).
Except this I never really saw a requirement for the constantly running service because:
A) Intent listeners (Manifest registered BroadcastReceivers) are quite a useful feature and using them as you know is usually enough for many use-cases (for example showing notifications).
B) If scheduled execution is a must one can subscribe to alarm events.
C) I know that service in Android is quite different then for example in Windows since in Android services are just a "package" to organize your code in and have a the system manage the lifetime of the object. Services use the Main Thread but it's customary to spawn new threads in them.
D) In the development documentation services are suggested for network communication and background calculations but I don't get why you should not just use AsyncTasks for that. I am a big fan of these and use them extensively for lot of things from downloading data from the internet to doing FFT calculations under time critical conditions.
E) I get the usefulness of Foreground services but why are people using background services so much (excluding the system apps).
Those are my thoughts about the SERVICE and I hope someone with more experience will be able to explain these PROS and CONS (along with others that I probably missed).
When should one implement a service?
When you have work -- delivering value to the user -- that:
Needs some time to complete, perhaps longer than you have time for in the component wishing the work to be done, or
Is delivering that value under user control (e.g., music player, controlled by play/pause buttons in a UI), or
In rare cases, needs to be running continuously, as it delivers value continuously
there are quite a lot of them running and I doubt it's just a poor application design
Some are likely to be poor implementations, either due to technical misunderstandings, or other concerns (e.g., making marketing happy) trumping making users happy.
It was a background sound recorder and I was using it as Foreground service with notification since I wanted buttons to be able to control it (like music players do for example)
That is a reasonable use for a service, IMHO.
Intent listeners are quite a useful feature and using them as you know is usually enough for many use-cases (for example showing notifications)
I assume that by "Intent listeners" you mean manifest-registered BroadcastReceivers. In that case, if the work to be done by the BroadcastReceiver will take more than a millisecond, that work should be delegated to an IntentService for completion. onReceive() is called on the main application thread, and it is not safe for a manifest-registered BroadcastReceiver to fork a bare thread, as the process could go away shortly after onReceive() returns. However, in these cases, the service is usually short-lived (e.g., do some network I/O and disk I/O, then go away).
In the development documentation services are suggested for network communication and background calculations but I don't get why you should not just use AsyncTasks for that
An AsyncTask is a fine solution for background work that is:
Requested by the UI (activity or fragment), and
Will take less than a second or so, and
Is non-critical
For example, if you are downloading avatars to show in a ListView, AsyncTask is probably a fine choice, whether you use them directly or use some image-fetching library that uses them internally.
Conversely, if the user buys an MP3 through your app, and you need to download that MP3 file, an AsyncTask is not a good solution. That could easily take over a second. While the download is going on, the user could switch away from the app (e.g., press HOME). At that point, your process is eligible to be terminated... perhaps before your download is complete. Using an IntentService to manage the download is a signal to the OS that you are really doing work here, adding value to the user, and so the process will be left alone for a little while.
Note that if the background work might take 15+ seconds, WakefulBroadcastReceiver or my WakefulIntentService is probably a good idea, so the device does not fall asleep while you are trying to wrap up this bit of work.
I can name some of the Service uses from my experience:
to implement
location listener,
sound module, generating various voices
in app content updates,
API, provide services to other apps
in app billing
Communication with webservices (if requests frequency is high)
actually (excluding 5.) they all are working for the whole app duration, they are using some of the other android services, also they manage their state. I suppose one of the important thing here is state management during application life cycle changes.
I prefer to look at AsyncTasks in a same way as Executors (ExecutorService), they should be executed sequentially and for small tasks.
In the android website, you can find a table when to use Service, Thread, or WorkManager (the new API for scheduling jobs, currently in alpha as of this comment posted). https://developer.android.com/guide/background/#table-choose
The website also state that you need to use started service only as last resort. The Android platform may not support started services in the future. Refer to this link https://developer.android.com/topic/performance/scheduling#services
You should avoid using started services that run perpetually or perform periodic work, since they continue to use device resources even when they aren't performing useful tasks. Instead, you should use other solutions that this page describes, and that provide native lifecycle management. Use started services only as a last resort. The Android platform may not support started services in the future.
If you consider UI and bound services, u would think that both can exist and not be doing anything for certian periods. In such scenarios, your UI can be recreated a lot of times however service does not. And this is where service is important. Lets say you are processing images and then rotate device you want processing to continue while UI is being recreated. You recording a voice and then rotate device. These are one of the places where I find service very important. (Having lot of heavy data processing, interaction with web, that could be few seconds)