I am developing an application in which we maintain a mqtt connection to the server to receive jobs from server in real-time.
Currently we are using an approach in which we use a foreground service to keep the connection alive even when the app is killed.
The problem is that the long running service drains battery so fast. And also I'm not sure how it is gonna react in devices from different vendors.
For example in Xiaomi devices, if the auto-start setting is not enabled for the app, the service can not start in foreground when the application gets killed. I've solved this problem, but I'm not sure if it is going to work on all other versions of MIUI and other vendors.
Beside I've read that newer android versions are going to use machine learning algorithms to put battery consuming applications to sleep.
So I'm looking for another solution instead of foreground service. So I'm asking is it possible to implement this scenario with WorkManager? Is it a good idea to use WorkManager instead of foreground service? Is there a better solution for this?
Currently we are using an approach in which we use a foreground service to keep the connection alive even when the app is killed.
Android ensures that foreground Services keep running and if killed, starts them again soon. However it's required for foreground Services to post a sticky notification that for an always running background app, it may be annoying. There's another way! You can request Android to ignore battery optimizations for your app. Ignored battery optimizations apps are exempted from Android O+ background restrictions and can start normal Services (not foreground Services) at any time.
The problem is that the long running service drains battery so fast.
The Service doesn't drain the battery, it's the network activity that drains the battery. The network activity comes from the MQTT keepalive property. Also note that battery consumption depends heavily on the underlying network transport technology too. WiFi uses less power, but cellular networks use much more power. So, in order to maintain a reliable connection to the broker and also lower the battery usage, you should trade off the keepalive against battery usage. Here's a good article to tune the keepalive parameter:
Power Profiling: MQTT on Android
So I'm asking is it possible to implement this scenario with WorkManager?
No, WorkManager jobs are one-shot jobs, Android schedules them and runs them at a particular time in the future. In the meantime, your app's process may be killed and the broker sends you a message, then you'll receive the message when your JobService starts again, so that's not real-time anymore, it's now polling not pushing.
Related
I am developing multiplayer game using Socket.io library. it Works Well.
But, in android 7.0 and above, system automatically suspend all network work when my app is in background. (And I must need to keep alive my socket connection).
I research about it as described here.
but, i can't understand. So, Please provide solution for that.
Unfortunately there's bad news and some good news for you on this.
Bad:
Since android marshmallow and above, there's a concept of a doze mode. If the device stays put for some time (can't confirm the duration for this and not disclosed by google), the device will go into doze mode and will suspend all network activity. There will be short maintenance windows where in you will be able to do syncs and stuff. Small workaround, do not target 23+ apis, i say small because i have observed this to not work on some phones. Another way to potentially bypass this would be to whitelist your app from battery restrictions but according to google guidelines, i don't think your app will qualify for that.
Worse news is that start from API 26, background services will also get suspended completely when app is totally backgrounded and has no visible component (a notification or a foreground service etc...). So oreo will be worse.
Good:
You might not really want to constantly keep the socket open. Instead opt for bursts of syncs. I personally have a job run every 30 - 60 mins or so to try and sync up.
You can leverage the JobScheduler apis and it will automatically handle the doze modes and stuff and you can make them run periodically when there is internet connection. While the job is running, you can connect to your server, do your thing and shut the socket. This is what google wants and is pushing all devs towards.
UPDATE 19-Apr-2021
WorkManager is the new and the best way to deal with doze mode and background limit restrictions.
Another alternative would be to have a foreground service with an active notification displayed which would constantly be connected via your socket. This will be visible to the user and it will not only annoy them that you are constantly using their data, it can also be bad for the battery. Alternative to this again is using the job scheduler to schedule and run a foreground service periodically so as to be transparent while also syncing your data every once in a while. The latter approach is what WhatsApp does, they have a job running which syncs all incoming messages with a foreground service once in a while.
In Short:
You will not be able to keep it alive always. You can try doing it in bursts using one of the methods that i described and know currently (maybe there are other alternatives that i don't know, i have tested these and they work) You will have to compromise, sorry.
Our company is developing an android application that uses network communication to send GPS signals from devices. The devices are the same and they are all work tools, so we do not have to worry about battery draining, or etc. Currently the activity has a thread, which communicates with the server. The problem is that when the device is locked and it goes to sleep, the network communication breaks.
I've tried to put a partial wake lock to the onPause method to keep the CPU on, and release the wakelock in the onResume method, but it seems not to work. Any idea how to prevent the sleep, or keep flowless communication between the client and the server?
Unfortunately, it is the new behavior, You can read here:
https://developer.android.com/about/versions/nougat/android-7.0-changes.html
See the Doze section.
When a device is on battery power, and the screen has been off for a certain time, the device enters Doze and applies the first subset of restrictions: It shuts off app network access, and defers jobs and syncs. If the device is stationary for a certain time after entering Doze, the system applies the rest of the Doze restrictions to PowerManager.WakeLock, AlarmManager alarms, GPS, and Wi-Fi scans.
It can be solved by using Foreground Service like mentioned above in comments by #egoldx.
It is surely a bad practice to try holding a wakelock, even partial, all the time.
I'm developing Android app with background service. Service is running in its own process (like com.example.app:extProccess). Service creating WebSockets connection. But after less than 1 min after service started there is a disconnection on WebSockets, but service is alive (not killed by Android). After 20-30 min a connection is recovering.
Seem like device entered in Doze, but very soon.
This is observed only on some Nougat devices.
If I prevent battery optimization (android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) for this app service and websockets working correctly without disconnects.
My question is why Android limits network so quickly if my app in foreground? So how to hold networking for background service in this case without using android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS?
Starting from Android API 21(Lollipop), Google started giving more focus on battery optimisations. The problem comes is any service. One way to overcome this is to use Job Schedulers for your background tasks(documentation available here). Also, any task that uses android resources a lot will be terminated by the Android Framework. The only solution for your particular use case is to either optimise your code or use "IGNORE BATTERY OPTIMISATIONS" as done by you.
So I've made an Android video-calling app that tries to be available in the background so that the user may receive calls when the screen is off. I've noticed however that the app would be paused when the device went to sleep.
The solution I've found that worked was to rewrite everything to a service and then request a wakelock so the service wouldn't be paused during sleep.
Surely, since there are so many of these types of apps, there is a more elegant way to do this? A periodic check wouldn't work since you would want to take the call in real-time.
It depends on the Android version, for version older than 6 a partial wakelock is enough to keep the device awake, for Android 6 you also need a foreground service, that's a Service that calls startForeground() and shows a notification, but to keep the device awake has a big impact in battery usage.
You do not necessarily need to transfer all the code to the Service due it is the whole application that stays awake.
A more elegant solution to replace all this would probably be to use Push Notifications, it is what most messaging applications use. Firebase has Push Notifications.
I have a VOIP app that I would like to always run in the background to make it responsive to incoming calls. Reading through some forums I found running the app in the background would cause a battery drain.
Are there good practices that I should follow so as to run the app in the background?
Reading through some forums I found running the app in the background would cause a battery drain.
It is more that having something run all the time increases your opportunity to drain the battery.
Are there good practices that I should follow so as to run the app in the background?
Being a VOIP app already violates some of the "good practices". For example, you will need to (try to) have a service that runs forever, to maintain your open socket connection to the VOIP server. And, depending upon how your networking is set up, you might need to try maintaining a WifiLock, which will drain the battery.
Generally speaking, then, you just want to make sure that your service is doing as little as possible except when a call is in progress. For example, while you may need to send packets over to the VOIP server periodically to keep your connection alive, try to do that as infrequently as you can.
There are many smart VoIP applications that use Push Notification feature. That will not eat up as much battery, but you must have a consistent internet connection. One such option is Axvoice. Check out their apps at: http://www.axvoice.com/support/mobile-voip-applications.html
They will also run in the background like other apps, but the difference between Axvoice and other apps is you can reduce battery consumption because it will not be communicating with live servers all the time. Please have a look at this: http://www.wikihow.com/Save-Battery-Power-on-an-Android
Use a Broadcast Reciever. It is documented here
http://developer.android.com/reference/android/content/BroadcastReceiver.html
A BroadcastReciever will execute it's code when the specified broadcast is broadcasted through the system. In other words when you receive a call the system sends out a broadcast saying that there is an incoming call. If your receiver is made to pick up on that broadcast than it will react. Think of it like the Android system is broadcasting a lot of different radio stations and a BroadcastReciever is like a radio. You can set it to pick up whatever broadcast you want and execute some code when it does.