I have an app that connects to the Bitmessage network, i.e. is downloading and processing data from the P2P network all the time. Also, it should (optionally) only use WiFi/unmetered networks.
I've implemented this by using the JobScheduler, but unfortunately it has a timeout of 10 minutes (apparently even 1 minute on Lollipop).
So in short, how do I implement a service that
automatically starts when WiFi is available
automatically disconnects when a metered network is used
doesn't time out
works on all Android versions since Lollipop
As you've found, a JobScheduler is not the correct component for continuously running in the background. The correct component for that is a foreground service.
From your requirements:
automatically starts when WiFi is available
You should still use JobScheduler for this. Your JobScheduler doesn't do any work itself: it just starts your foreground service. You can use Firebase JobDispatcher if you'd like it to work back to API 14 and only need to run on devices with Google Play services.
automatically disconnects when a metered network is used
In your foreground service, you should programmatically register a listener for the CONNECTIVITY_ACTION Broadcast. In the callback, you should check the result of isActiveNetworkMetered() (available on API 16) and, if true, stop your foreground service.
doesn't time out
A foreground service has no time out: it'll continue to run until you stop the service. It is highly recommended that the notification required to make a service a foreground service have an action to allow the user to stop your service manually.
As mentioned, the job scheduler is not intended for tasks that run forever. That is what foreground services are for.
In your case, I'd suggest using a job to monitor for the startup constraints that you want (metered network and so on). When that job runs, you start a foreground service to do the actual work, and return false from onStartJob().
Then, while your foreground service is running, just watch for the loss of metered networking directly using the connectivity & network APIs, and shut down the foreground service when appropriate.
Related
In my App i am using the TimerTask with an Interval of 1s. If the App is in the background, I show the current Time in the NotificationBar. So every second in the onTick() Method I update the silent Notification. But with Android 10 it stops updating after few minutes. All Notifications are blocked, also the other channels.
Is there a new permission or another way to show the Time in the NotificationBar?
your application might be killed in background so that's why it stops showing the updates.
Try using workmanager for your app to run continuously below is the links
workmanager
Key features:
Backwards compatible up to API 14
Uses JobScheduler on devices with API 23+
Uses a combination of BroadcastReceiver + AlarmManager on devices
with API 14-22
Add work constraints like network availability or charging status
Schedule asynchronous one-off or periodic tasks
Monitor and manage scheduled tasks
Chain tasks together
Ensures task execution, even if the app or device restarts
Adheres to power-saving features like Doze mode
I need to upload a record of data from local DB to the server which also includes a video file which may be of about 30 MB size.
Above upload happens when the network gets available even when the app is killed.
Now for detecting network change, in Android N and above CONNECTIVITY_CHANGE and CONNECTIVITY_ACTION are deprecated, so broadcast receiver is not useful.
also, the CONNECTIVITY_ACTION is deprecated in API 28 (Pie).
Many answers suggest to use JobSchedular for such tasks but it is useful for smaller uploads.
refered this: Detect CONNECTIVITY CHANGE in Android 7 and above when app is killed/in background
WorkManager https://developer.android.com/topic/libraries/architecture/workmanager.html
So how can I detect the network change in Pie(API 28) when app is killed and perform the above mentioned upload task.
JobScheduler or WorkManager has a timeout of 10 minutes. If the upload takes longer than that, then you must use Foreground Service!
Considering the device's limited resources, starting from Android 8.0, Google has taken some strict measures in managing background task for the app. For any long running task, Apps must use Foreground Service so that users are always aware of it.
So after scheduling your task using either WorkManager or JobScheduler, you can start a Foreground Service in which you can do the process of uploading the video. (reference)
and in your Service you can use ConnectivityManager.registerNetworkCallback to listen for network connection. (reference)
I have been reading lately about how background jobs are done in Android (using Service, AlarmManager, JobScheduler, etc) and learned that these background task can go indefinitely even the app has already closed or device has screened off. I understand that the only they stop if they stop themselves or other components stop them.
Questions:
If I have a background job or an alarm that goes every 1 hour. Does it really runs forever until a component stop them? Is there an instance that the system will stop them?
What if I have periodic job or alarm that goes every 1 hour. Will they stop if I uninstall the app that started them? Cos I never read this part in any documentation.
Is there a way to check any running or pending background jobs/alarms in my device?
The explanation that is given about background tasks in your question only applies to Background Services, that to only in Android API Levels below 26.
Google recommends using JobScheduler or Foreground Service to do some work in background even when app is not in foreground.
Coming to you questions
No, If your using JobScheduler or Alarm manager the system will trigger your job to do your work depending on device idleness and conditions mentioned by you but the system can anytime come and stop your work in between when the conditions are no longer met.
If your are using JobScheduler it will inform you when system wants to stop by force so that you can handle it properly and reschedule if needed
When the App is uninstalled every job or alarm that is scheduled or in-Progress will be destroyed.
Yes, JobScheduler does provide a function 'getAllPendingJobs'
Note :
For works that should be scheduled or completed even when app is closed then try avoiding the use of Background Services or Alarm Managers.
JobScheduler is much more better replacement.
If you want to do some simple background work when the app is in foreground then try using HandlerThreads or AsyncTasks
I want to call web service in the background when internet is connected. If it is connected I want to call in every one hour if internet is turned off then stop the service. How can I? It needs to work for all versions from 16 to 27.
There is broadcast in android which notifies you if network status changed. In there you can register alarm manager for a period of one hour and check if the internet was connected then call the web service.
If broadcast informed you the network was disconnected then you can cancel your alarm manager.
Here is documentation for listening to network status change:
https://developer.android.com/training/monitoring-device-state/connectivity-monitoring
and here is good tutorial about using alarm manager in android
https://en.proft.me/2017/05/7/scheduling-operations-alarmmanager-android/
also google introduced workManager which does this work for you in the very simple way
The WorkManager API makes it easy to specify deferrable, asynchronous
tasks and when they should run. These APIs let you create a task and
hand it off to WorkManager to run immediately or at an appropriate
time. For example, an app might need to download new resources from
the network from time to time. Using these classes, you can set up a
task, choose appropriate circumstances for it to run (like "only while
device is charging and online"), and hand it off to WorkManager to run
when the conditions are met. The task is still guaranteed to run, even
if your app is force-quit or the device is rebooted.
here is link to documentation :
https://developer.android.com/topic/libraries/architecture/workmanager
Our app can connect to a HVAC device, and need to sample its state every 10 seconds.
The HVAC device expose a Modbus interface and CANNOT buffer samples. We ACTUALLY need to wake up the service every 10 seconds. A typical sample session last from 1 hour to a few hours.
(There are various connection types/cables/bridges: OTG + RS232 USB converter, TCP trough a RS232/TCP bridge, Bluetooth classic and BLE through RS232/BT or BLE bridges.)
Of course the user should be able to turn off the display to save battery, and to navigate to other apps, while the sampling session is taking place.
Until Nougat 7.0 our working solution was:
Start an IntenService, then set it to Foreground Service
Bound to that service, so it's also a Bounded Service (to stop it, propagate interaction with the HVAC device from the GUI, etc.)
Acquire a PowerManager.PARTIAL_WAKE_LOCK
Use a Thread.Sleep() for the 10 seconds cycle, but also to manage timeouts in the transport implementation of the various connections
Should I post the code? The relevant parts are most common boilerplate.
Despite having no documented guarantees, Thread.Sleep() with a PowerManager.PARTIAL_WAKE_LOCK in a Foreground Service was working perfectly until Nougat 7.0
On our testing Oreo device, both compiling targeting API 26 and 23 (as our previous released version), while not interacting with the app activities (turned off display, other apps in foreground etc.), the service does not wake up, it sleeps until the first interaction with the app.
To be able to start a foreground service on Oreo targeting API 26, I implemented Bikram Pandit's solution from Android O - Old start foreground service still working?.
Nothing changed.
I asked for a Battery Optimizations exception, with ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS (as descripted in https://developer.android.com/training/monitoring-device-state/doze-standby#whitelisting-cases ), and granted it. Nothing changed. (And the app was working without it until Nougat 7.0)
The documentation about Oreo's Background Execution Limits, https://developer.android.com/about/versions/oreo/background, states that Bounded Services or Foreground Services should NOT be subjected to these limits. And yet the service doens't wake up.
AlarmManager cannot be used, since from Oreo it can fire at most every 9 minutes, even with setAndAllowWhileIdle() nor setExactAndAllowWhileIdle(). (Again in https://developer.android.com/training/monitoring-device-state/doze-standby#whitelisting-cases)
I also tried using a wait(sleepTime) instead of the Thread.sleep(): it's even worse, it doesn't even wake up when restarting interacting.
I stopped short before re-implementing as a JobIntentService or using JobScheduler/JobService, to reframe every sample as a job, but:
IMPORTANT: I would still need the Thread.Sleep() in some of the transport level connection implementations, will that wake up during a job?
Would JobScheduler actually allow to run jobs every 10 seconds, or would it bundle them together on Oreo? We actually need a sample every 10 seconds. We probably could relax to 1 minute, but not any larger.
Can I retain very complex state (my ModbusDevice object) in JobService, to share it among all those jobs or there would be limitations?
Again, should I post some code? It's most common boilerplate.