I need to implement a background process in an iOS app, that performs a job every 60 seconds. I know this can only be done while the app is in focus, but I do want this job to finish running in the background after the app is closed. I will use GCD to dispatch a timer that calls my job asynchronously every 60 seconds using either dispatch_async or beginBackgroundTaskWithExpirationHandler.
I am wondering which method is the best, or if they are essentially the same. Is it okay to use beginBackgroundTaskWithExpirationHandler to execute a job even while the app is in the foreground? Or am I better off trying to cancel the job when the app state changes, and then restart the job as a background task?
-beginBackgroundTaskWithExpirationHandler: doesn't run code on a background thread/queue. It tells the OS that you are going to continue doing work when your app is not active.
The two serve completely different purposes.
Related
There are different ways to run tasks in the background in Android and iOS respectively. I have found What is the best way to schedule task in android? as well on stack overflow.
I am wondering which is the best way using react-native only. Would it be good enough to use setInterval or setTimeout for tasks that have to run daily or every few hours?
Would not those tasks be killed by the OS?
Any ideas or suggestions?
I will answer my own question to see if this information can be of used by anyone looking for it.
Since the different mobile OSs tend to kill background jobs, or stall them to save battery, there are few deterministic methods to schedule tasks in react native. I use a combination of the following:
Offload timers to the background, which work with the app in both fore and background https://github.com/ocetnik/react-native-background-timer (!If you use create-react-native-app you must eject it)
Use a background-fetch for iOS and HeadlessTask in Android, here is a decent library https://github.com/jamesisaac/react-native-background-task
Use geolocation updates to wake up the app and start threads https://github.com/mauron85/react-native-background-geolocation.
I guess you can follow similar strategies using bluetooth wake-ups.
Push notifications from a server to ensure deterministically that the app wakes app (except it having been killed by the OS). In iOS, ensure that you call notification.finish() to avoid being discriminated by the task handler algorithm.
For Android you can try to use AlarmManager API https://github.com/vikeri/react-native-background-job.
Beware of the dragons: your app might be closed if it abuses execution time or memory usage after a system wake up. You may have to rehydrate all listeners after the phone was left without battery. So the user still needs to interact heavily with your app.
Update:
From Android O there are very strict background execution limits. When using a HeadlessJSTask service, ensure that it is launched as a foreground service if you want it to last longer than a few seconds. It may require a notification with it. Take into account that only loading the bundle can take up to a few seconds, depending on your app and the device.
As a matter of fact there is not any sufficient way for that. but we can remark mauron85 as a way which is better then others on android but also it doesn't work perfectly on IOS. for example if app has killed by user the job would not keep working or there is not any control of job execution quantity the job fires each time device changes its position.
other components like react-native-background-fetch and react-native-background-task have the limitation of job execution period(the job repeats after each 15 minutes and there is no way to decrease this time period) and they just work on android.
it would be great if Facebook react native has some practical solution for this problem.
I know how waitpid(-1...) allows me to wait until all children have finished, such as waitpid(-1, &status). But how can I wait until all background processes are finished? Someone suggested that I can use the same waitpid (in a loop?) to achieve this but I don't see how.
To be clear, I'm implementing a shell, and need to add a new built-in command wait, which waits until all background jobs have terminated before returning to the prompt.
I read somewhere else on SO that "You will also want to call waitpid() with the WNOHANG option regularly - say, immediately before you display the shell prompt. This will allow you to detect when the background process has exited or stopped " But again, child != background. So even that I don't believe.
Edit:
I ended up just doing while(wait(NULL) > 0); and that's it, it worked. But what I'm still confused about is don't I WANT to make a distinction between foreground and background because the wait I'm implementing only waits for the background processes, and all children are equal in the eye of wait() or waitpid().
So again, the children I'm waiting for by using wait() or waitpid() aren't necessarily background processes. Am I wrong?
Since you ask in the context of implementing a shell, and evidently your shell supports enough job control to have a concept of background processes, it is reasonable to suppose that your implementation will have a table in which it tracks background jobs. That table can and should track the PID of the process associated with each job.
Having those PIDs in hand, you can waitpid() for specific background jobs until there are no more in the table, or you can waitpid(-1) to collect
any and every job, in a loop, until there are no more background jobs in the table.
If you want to implement background process (and job control) and catch their termination (at least) you must set a signal handler for SIGCHLD, and call wait(-1) inside it. This will let your shell receive asynchronous notifications of background processes termination. You may have a look at Catching SIGCHLD for example and discussion about this.
I have a Windows Phone 8.0 app that I'm porting to 8.1. In 8.0 I depended a lot on BackgroundWorker to execute tasks that I didn't want consuming the UI thread.
I would create the BackgroundWorker, define the DoWork() delegate and then immediately execute RunWorkerAsync()
Now in 8.1 I can't use BackgroundWorker anymore. Instead, I need to create Tasks implementing IBackgroundTask and use IBackgroundTrigger objects run them.
It seems like I need to jump through a lot of hoops just to run code on a different thread. If I want to run a background task immediately to I create a time triggered background task with a new oneShot TimeTrigger() with 0 freshness minutes? That seems like a bit of a hack..
Is there an alternative to BackgroundTask? Should I be approaching my requirements differently?
To run anything on a different thread, all you need to do is call:
Task.Run(delegate() {
// The work to be executed on the background thread
});
You can also await this in a non-blocking way, in case you want to do something after the work in the different thread has finished.
IBackgroundTask is something completely different. It's used when you want to have some code executed on some event when the app is not running. For example, if you want to update the Live Tile every 30 minutes, you would do this using a background task, implementing that interface.
I have a strange issue. My app gets killed if my UI thread is blocked for long time ( say 10s). I want to repeatedly take screenshots after updating view in a loop. This is a time consuming process. But my app gets killed and no memory warning is received. My question is will my app get terminated if UI Thread is blocked for long time?
This is normal. Instead of letting apps freeze, iOS watches each app if they are taking a long time in the UI thread. Is there any reason you have to take the screenshots in a single run loop? Why not just setup a CADisplayLink callback and take just one screenshot every execution?
What is the right way to check for data in remote database through http requests in objective c iOS. I am thinking of an nstimer that is called every 5 minutes. The nstimer will trigger a function with a thread in it. Is this the right way? Is this going to work when the app enters the background?
Any help appreciated.
The thread (as like all execution in your program) will pause when entering the background - and if it was waiting on a network response, that response will fail after the app returns to the foreground.
Moreover, you need to explicitly tell iOS when you are beginning a task that you would like to continue in the background (with beginBackgroundTaskWithExpirationHandler: on your UIApplication singleton) and when you have finished that task (with endBackgroundTask:). However, that is only up to a maximum of ten minutes, so I daresay you won't be able to, say, continue your NSTimers in the background. But yes, the method you have described is fine for when the application is in the foreground.