Syncing with server in specific interval at non-active hours - android

I want to sync the data with server between 12 am - 6 am only.
I have solutions like WorkManager and sync adapter at my disposal.
But some manufactures put restrictions on these work managers and syncadapter also.
What is a sure shot solution that a network request will can be made between these non active hours(most users are not using the app) ?

There is no sure solution. This is Android. Every vendor can do whatever they like.
What restrictions you are talking about? Because you are saying "some vendors"? In general Android applies restrictions related to how much time you can be executed per 24 hours period and how much network you can use. It is dependant on the Power Bucket you are in. And the Power Bucket itself depends on how often the user interacts with your app. Check here:
https://developer.android.com/topic/performance/power/power-details
You can implement a dialog asking the user to exempt you from Battery Optimization. This will fix the restrictions on most vendors. Check here:
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases

Related

Android recommended and reliable API for periodic background work?

I've been using WorkManager to create notifications for my app. For my purposes I figured PeriodicWorkRequest is the most fitting, but after a bit of testing and reading online it's seems extremely unreliable. Using the minimal interval (15 minutes), and the app being closed, the worker woke up 5-6 times and then seems to be killed.
So how does one go about creating background work that wakes up in reasonable time intervals? What is the best approach for creating event-based notification? My idea was checking for the event (for example, checking for something new in the database) in small time intervals (with 15 minutes also being less than ideal), but seeing as it doesn't work well with PeriodicWorkRequest and is also the recommended approach as per the documentation, what exactly are my options?
Basically, the idea of Android is for you not to be able to do what you want to do because we as developers try to kill the battery.
You need to see how the evolution of the restrictions goes:
Version 6 - Doze:
https://developer.android.com/training/monitoring-device-state/doze-standby
https://developer.android.com/about/versions/marshmallow/android-6.0-changes#behavior-power
Version 7 Another state of Doze with even more restrictions:
https://developer.android.com/about/versions/nougat/android-7.0-changes#perf
Broadcast Restrictions:
https://developer.android.com/guide/components/broadcasts
https://developer.android.com/about/versions/nougat/android-7.0-changes#bg-opt
Version 8.0 Background execution limits:
https://developer.android.com/about/versions/oreo/background#services
Version 9 StandBy Buckets - where depending on how the app is used you have different resources to use - like time to wake up the app, time to use the Network, etc
https://developer.android.com/about/versions/pie/power#buckets
https://developer.android.com/about/versions/12/behavior-changes-all#restrictive-app-standby-bucket
https://developer.android.com/topic/performance/appstandby
Battery Save improvements:
https://developer.android.com/about/versions/pie/power#battery-saver
Power Management Restrictions - really important.
https://developer.android.com/topic/performance/power/power-details
Version 11 and 12 App hibernation
https://developer.android.com/topic/performance/app-hibernation
Long story short - you need to prevent all these restrictions to harm your work. But you need to comply because it is better for the user.
But there is no API that will just say - "f**k all these restrictions and do whatever the dev wants to do."
If you need exact timing - you need AlarmManager.
If you do not know when you need to do your work and depend on the outside - Push Notifications which then can transfer the work to the WorkManager.
If you need periodic work that is not time-critical - you might not use the AlarmMangaer and be sure that the work is finished, but you can't be sure when, because there are many restrictions and the priority will be saving the resources.
Also, you can ask the user to be exempted from Battery Optimization:
https://developer.android.com/training/monitoring-device-state/doze-standby#support_for_other_use_cases
If you want to know why exactly the work is not executed you need to check the JS dump and see what restriction is not satisfied:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/debugging#use-alb-shell0dumpsys-jobscheduler

How to perform background service while battery optimization is active

I currently use the Firebase JobDipatcher to perform a periodic task in the background. The problem is the background service only gets executed when battery optimization is disabled and standby state of the app is manually set to ACTIVE under developer options. Is there a way to do the background task without manually changing all this, because i cannot ask every user of the app to do so. And saw many posts that google will suspend the app if the power management permissions are requested within the app. Any help would be much appreciated.
In one word answer is BIG NO
As developers remains unhappy with such small answers, so i am starting the HUGE theory, here we go -
STRATEGY NO - 1 :
Use AlarmManager
All alarms are forgotten by the android on Reboot, so keep all alarms in app Sqlite database, implement BOOT_COMPLETED broadcastreceiver, which is still allowed to define statically & re-schedule all alarms by taking from apps database.
All your project & hard work will work as per your plan, but only on emulators
Because in real world, 99% devices are with chinese ROMs like MIUI, OxygenOs, ColorOs, FunTouchOs, .. which never triggers your apps BOOT_COMPLETED broadcastreceiver.
Because they all are ahead in saving battery life, by stopping all apps background services..!!
Nice question,:- Then why whatsapp, facebook, tiktok, twitter processes are getting executed normally...?? And why not mine...??
Nice answer,:- If Chinese ROMs disallowed above apps background services then no one will buy their devices..!! And lets do not talk about your application as it does not affect the world in any way, your app is useless ( as per chinese ROMs ) , so they disallows all other packages background tasks..!!
All Chinese ROMs never triggers AlarmManagers if the app is not in foreground. Never triggers if app is removed from recents
In short & sweet treat Alarmmanager as depriciated.
STRATEGY NO - 2 :
Use FirebaseJobScedular as you stated
If user updates Google Play Services , then system forgets all jobs..!!
Again FirebaseJobScedular was developed to run all jobs on every device in market, but as chinese ROMs never allows any processes / classes / Jobs from their own wishlist, this makes no sense again.
This library is depriciated by google now.
STRATEGY NO - 3 :
Use WorkManager, the new library which is taking place over the FireBaseJobScedular officially.
Again the same thing, WorkManager is still in development, you can use it, but the case is same that many chinese ROMs discard this libraries jobs too..!!
STRATEGY NO - 4 :
Run all time foreground service.
BOOT_COMPLETED from your broadcastreceiver start it again.
But even if you use START_STICKY, many chinese ROMs used to suspend its tasks, you can see it in foreground, but works gets suspended.
STRATEGY NO - 5 :
Use WakeLocks
But as the android version changes, it has changed to the newer newer implementational strategies in every versions
STRATEGY NO - 6 :
Programatically make battery optimisation off for your app, but google discontinues your app from app store in such case
Navigate user to battery optimisation settings intent, by opening it programatically & let him choose battery optimisations on his own, is allowed by google
But as no user is in market, who knows it, as even many developers dont know this yet, how end users can understand it..??
Again if power saving mode ( it is different than battery optimisation okay ) is made ON by user then, no way your battery optimisations is never considered.
What the ***** should i do then ...?
Nothing as developer.
Train your support / sales team to "LOCK" your app in the recents of every phone, after which, users are unable to swipe it away from the recents, even if it is swiped away, your all above strategies will work & your jobs / alarms / tasks will be executed, as it happens on your android emulator or as on stock android
Train your support / sales team how to make battery optimisations to "Do not optimise for this app" too..
It is so out of the box solution..??
Yes, it is. As in the market you will notice 1% stock android devices and 99% chinese modified ROMs
This all knowledge came to me after i lost last 9 to 10 years resolving the same problem, Hussshhhh

Sending data from Android device to server in the background with minimal user impact

I have an app that generates data that needs to be sent to my server eventually (several hours of delay are no problem at all). I would like to do this with minimal impact to the user, which means to me:
Minimal battery use
No extra permissions, especially not "sketchy" ones
No other strange changes to the system (see example later)
So far I've found three approaches, that all have some serious problems:
Using a SyncAdapter triggered by a network message:
Technically, this sounded like the perfect answer to the problem: Have the system call a service in my app whenever it's doing something on the network anyways. That way, the network is guaranteed to be available, there's barely any extra battery use, since the radio is already on, and the whole thing happens in the background...
And then I tried actually implementing it...
Unfortunately, this approach requires some weird modifications to the system: My app needs to create a new dummy account for the sync-process, even if my app doesn't otherwise use any accounts. And unfortunately, this account cannot be hidden from the user, so now my app is listed when the user clicks "Add Account" in the System Settings, but inside the app, there is no indication of user accounts anywhere... Also, I need to request all sorts of strange permissions, like "Create accounts and set passwords", "Toggle sync on and off", and "Read sync settings". Why would an app that doesn't even provide me with a user account require a permission to set passwords on my device??? Not cool... Delete!!!
Using a BroadcastReceiver and checking for connectivity when it fires:
This requires permission to "view network connections" and possibly even "view information about Wi-Fi networking, such as whether Wi-Fi is enabled and names of connected Wi-Fi devices" ... Why would this app care about my wi-fi or network neighborhood? Creepy... Not getting installed on my device...
The nice thing about this approach is that a network connectivity change likely only happens while the radios are turned on (at least a change to the "available" state). So, if I use this event to trigger an upload (attempt), the battery-impact will be minimal as I won't cause the radio to turn on just for the upload. Unfortunately, this event will probably not be called very often. And to make matters worse, from the docs it sounds like the BroadcastReceiver will only be called while my app is in the resumed-state. So, I won't even be able to make use of events while my app is paused... I.e. using these broadcast events will only be slightly better than option 3:
Just blindly initiating the upload at regular intervals and, if it fails, retrying it again later:
This approach doesn't require any strange permissions and doesn't mess with any system settings. But, clearly, it is the worst I can do for battery use. So, while it's workable, I'd rather find a smarter alternative...
Is there a way to fix the issues of one of the first two approaches? The optimal solution would be a SyncAdapter without a dummy user-account, or, at least, with a hidden one, or one that already exists in the system... But many hours of searching didn't yield any usable answers...
Or is there another better way altogether?
#CommonsWare pointed out two further approaches:
Using JobScheduler:
This allows scheduling jobs for future execution that depend on certain network connectivity or even a certain charging status of the device. It says that it tries to batch job executions for all applications on the system, which may save battery by avoiding additional radio activation, if other apps also have jobs executing that access the network. But if my app is the only one needing to do a network request, I don't think the JobScheduler provides quite the same amount of battery-saving as a network-tickle-driven SyncAdapter would. This is just a guess based on my current understanding, though.
The big issue with using the JobScheduler is that it requires API level 21, i.e. Android 5.0+. For some apps, this might be acceptable, but for me it's not...
Using Google Play Services' Cloud Messenger API, specifically GcmNetworkManager:
This seems to provide pretty much identically the same functionality (except for controlling the retry-backoff-strategy) that the JobScheduler does, except it is available on all devices that have Google Play Services v7.5 or higher installed. Google Play Services is available for devices as far back as Android 2.3, but v7.5 was only released end of May 2015. So, while v7.5 is also available for Android 2.3, it is not guaranteed that it is installed.
To use it, the (supposedly very lightweight) Google Play Services API library needs to be added to the app, which provides the method GoogleApiAvailability.isGooglePlayServicesAvailable(...) that can check if Google Play Services is indeed installed and updated to the version required by the API library. To maximize the chances that this is the case, the API library v7.5 can be added to the app (see here and here for how to get it). If the check fails due to a user-resolvable problem, the library even provides the required dialog to prompt the user to fix the issue (e.g. run an update, ...).
The major advantage of this approach is that it does not require any extra permissions for the app and it doesn't rely on any other changes to the system (mock user accounts, ...). So, it is entirely transparent to the user.
I also found one additional approach, somewhat related to point 3 above:
Using AlarmManager.setInexactRepeating(...):
The AlarmManager also tries to batch callbacks together, just like the JobScheduler and GcmNetworkManager do. In fact, looking at LogCat that sometimes reads "AlarmManager: Checking for alarms... com.google.android.gms", it seems that GCM, and probably also JobScheduler, use the AlarmManager to trigger their execution. The features missing from the AlarmManager are: Suppressing a callback based on network connectivity or battery charging status, and automatic retries of failed executions with a back-off schedule. Technically, one can easily add these features, but some of them, like checking for network connectivity, might require additional permissions.The major advantage of this approach is: It's available on almost all devices (starting API level 3).
Currently I have the GcmNetworkManager approach implemented (point 5) and it works as expected.
But I'm actually considering moving to AlarmManager.setInexactRepeating(...) (point 6) to maximize compatibility. Checking for the device charging state seems to be possible without extra permissions and rather than checking for network connectivity, I can just fire off the http request and check whether it failed... The only feature I would be missing is determining whether the user is on a metered connection or not. And, of course, it will be a bit of work to implement retries, back-offs, ...
Update:
It seems like JobScheduler actually does detect existing network activity (see this JobScheduler introduction), which might make it superior to just using the AlarmManager, and pretty much as good or better than SyncAdapters... The GCM documentation also claims callback optimization based on current network activity (not just availability)... So, I guess the optimal solution would be to use the JobScheduler where available and fall back to GCM where it's not and to the AlarmManager where GCM isn't available either... Yuck...

Is httpPost too demanding to be used in an Android service?

I need my app to receive notifications, but my boss does not want to rely on Google Cloud Messaging so I will use httpPost in a background service instead for periodically check for new messages.
My question is: will that be too demanding for the battery and data consumption? Do you know a better option?
Thank you.
Edit:
This is an app for a delivery store. The messaging starts when you ask for something and ends when you receive the item. The message query will be every minute for about 10 or 20 minutes.
In general, this would not seem like a good idea. The scenario you describe seems like a perfect fit for GCM. I would first try to convince your boss to reconsider. :)
"Polling" a server, even for a brief connection which transmits hardly any content, means the device must be woken (from a low power state) and the radio turned on, and it will stay on for a significant time. The impact on data consumption will probably be insignificant, but battery usage will be a concern.
In case it cannot be avoided, you should check Minimizing the Effect of Regular Updates section of the Efficient Downloads referenced by #CommonsWare in the comments.
Also, Reto Meier gave an excellent talk on this subject at the 2012 Google I/O. His series on Efficient Data Transfers is also very informative. Hope it's helpful.

Android app: decrease battery usage

I just finished an app that synchronizes its data with a server (runs SyncAdapter on background). I installed it on my phone, let it run on background (I barely used my phone) and I found out that the 23% of my applications' battery usage belongs to my app, so I really need to decrease its battery usage.
Right now I have the sync time set to 30 seconds. It's a multi-user app and if other users interact with you you get a notification, I can't set a sync time too high (actually I wanted to decrease it until I saw the battery usage).
In each synchronization it ALWAYS asks the server for any changes and checks for changes in the local database. If there are changes in the local database they are sent to server, and if we retrieve changes from the server they are applied to the local database.
Does anybody know about some tips to reduce battery usage?
Probably the best that you can do is to implement GCM (Google Cloud Messaging) using pushing instead of polling.
In this way you will be able to get a "tickle" when something new happened and you will know when ask to the server for datas.
A network poll each 30 seconds is very aggressive. I recommend you read this article from Google : http://developer.android.com/training/efficient-downloads/index.html
However, if you really need to request the network that often, I don't see any magical trick for you...

Categories

Resources