How to perform an task in the background? - java

I want to use WorkRequest to run a task in the background on a daily basis. But I have two problems:
These codes are executed again each time when the app runs.
When the app is closed, the code will not be executed.
I also want the code to run when the program is closed

You can either use a Handler or you can use workManager.
WorkManager works on devices runnig Android 5.0 or higher.So, if your min sdk version is higher or equal to that , prefer using that.Work Manager is used for deferrable tasks generally like sending analytics event etc.

You can use WorkManager.enqueueUniquePeriodicWork() method to schedule your work. There will be only one instance of that work.
ExistingPeriodicWorkPolicy.KEEP keeps the existing work and ignore the new request each time the app is started.
Example:
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"UNIQUE_TAG",
ExistingPeriodicWorkPolicy.KEEP,
yourWorkRequest
)
Source: https://developer.android.com/topic/libraries/architecture/workmanager/how-to/managing-work#unique-work

There are several ways to perform a task in the background threads and not use it from the UI thread.
using the AysnkTask. Tutorial : AsyncTask
using RxJava. RxJava helps you to perform tasks in other threads and even manage the consequence of a task to perform in which thread. Tutorial RxJava

Related

Where is the Immediate Scheduler in rxJava3?

In rxJava 1 there was Scheduler.immediate() which let you schedule work on the current thread. In rxJava 3 I can no longer find this scheduler.
Does anyone know what the replacement for Scheduler.immediate() is in rxJava 3?
My use case:
I have a client-side API which I use to subscribe to an infinite stream of events (e.g. a news feed) from a remote server. The API notifies me of events via a callback which I register:
Observable.create(emitter -> apiClient.registerCallback(event -> emitter.onNext(event)))
.observeOn(Schedulers.immediate()) // I'd like downstream operators to run on current thread
.map(myFunc);
However, the API calls my callback from a different thread. I wish to run downstream computations like myFunc on the current thread (the one that created the Observable) so as not to block the API's thread.
AFAIK, in RxJava 3 you can employ ImmediateThinScheduler to obtain the same effect.
Although it's kept in the internal package, you can use it.
The API is so simple you can actually create one yourself if you don't want to depend on their internal package.

I have scheduled a periodic work by calling the enqueueUniquePeriodicWork() method. How to get result?

I'm using WorkManager 1.0.1 and I have a question.
For example, I have scheduled a periodic work by the following code:
WorkManager.getInstance().enqueueUniquePeriodicWork("work", ExistingPeriodicWorkPolicy.KEEP, myPeriodicWorkRequest)
How do I figure out if this request was "declined" due to the work with the same name had already been scheduled or if everything was okay and the work was sucessfully scheduled?
You can use the myPeriodicWorkRequest id value to retrieve the work information.
For instance, you could call WorkManager.getInstance().getWorkInfoByIdLiveData(myPeriodicWorkRequest.id) in order to get a live data for observing changes in the scheduled work.
Enqueuing your unique work using ExistingPeriodicWorkPolicy.KEEP means that you are asking WorkManager to enqueue your WorkRequest only if there isn't another WorkRequest, connected to the same unique name, in a "non-final" state.
If you need to always enqueue the new WorkRequest you should use ``ExistingPeriodicWorkPolicy.REPLACE`.
If you think that you need to know if the new WorkRequest has been enqueued or not you are probably trying to shift to much of your application context into WorkManager.

How to check status and cancel an asynchronous task?

Currently, I am working on a rest API through which client can submit a forever running task and it should return started confirmation if there is no error. The client should be able to submit any number of similar tasks. There should be a functionality to check the status and cancel any task. Currently, I am trying to do it in Java using Spring. How should I approach the problem?
I was able to create an asynchronous task in Spring each time I sent a post request. But till now unable to figure out how to check the status and cancel any task.
Threads you can use here.
Create a job executor class responsible for running the task.
Make a callable. So, you would be able to get the result in the Future.
Use BlockingQueue for the task to store and pick from it (you should because of processor i.e. dual/4 cores).
Use Runtime Class to get the Cores available and Run the thread in cores-1.
No. of thread = Available cores-1.
for cancellation, you can use a flag that mapped to respected stored Thread. Check that flag and return if thread started at any point of time

How can I ensure that my Android app doesn't access a file simultaneously?

I am building a fitness app which continually logs activity on the device. I need to log quite often, but I also don't want to unnecessarily drain the battery of my users which is why I am thinking about batching network calls together and transmitting them all at once as soon as the radio is active, the device is connected to a WiFi or it is charging.
I am using a filesystem based approach to implement that. I persist the data first to a File - eventually I might use Tape from Square to do that - but here is where I encounter the first issues.
I am continually writing new log data to the File, but I also need to periodically send all the logged data to my backend. When that happens I delete the contents of the File. The problem now is how can I prevent both of those operations from happening at the same time? Of course it will cause problems if I try to write log data to the File at the same time as some other process is reading from the File and trying to delete its contents.
I am thinking about using an IntentService essentially act as a queue for all those operations. And since - at least I have read as much - an IntentServices handles Intents sequentially in single worker Thread it shouldn't be possible for two of those operations to happen at the same time, right?
Currently I want to schedule a PeriodicTask with the GcmNetworkManager which would take care of sending the data to the server. Is there any better way to do all this?
1) You are overthinking this whole thing!
Your approach is way more complicated than it has to be! And for some reason none of the other answers point this out, but GcmNetworkManager already does everything you are trying to implement! You don't need to implement anything yourself.
2) Optimal way to implement what you are trying to do.
You don't seem to be aware that GcmNetworkManager already batches calls in the most battery efficient way with automatic retries etc and it also persists the tasks across device boots and can ensure their execution as soon as is battery efficient and required by your app.
Just whenever you have data to save schedule a OneOffTask like this:
final OneoffTask task = new OneoffTask.Builder()
// The Service which executes the task.
.setService(MyTaskService.class)
// A tag which identifies the task
.setTag(TASK_TAG)
// Sets a time frame for the execution of this task in seconds.
// This specifically means that the task can either be
// executed right now, or must have executed at the lastest in one hour.
.setExecutionWindow(0L, 3600L)
// Task is persisted on the disk, even across boots
.setPersisted(true)
// Unmetered connection required for task
.setRequiredNetwork(Task.NETWORK_STATE_UNMETERED)
// Attach data to the task in the form of a Bundle
.setExtras(dataBundle)
// If you set this to true and this task already exists
// (just depends on the tag set above) then the old task
// will be overwritten with this one.
.setUpdateCurrent(true)
// Sets if this task should only be executed when the device is charging
.setRequiresCharging(false)
.build();
mGcmNetworkManager.schedule(task);
This will do everything you want:
The Task will be persisted on the disk
The Task will be executed in a batched and battery efficient way, preferably over Wifi
You will have configurable automatic retries with a battery efficient backoff pattern
The Task will be executed within a time window you can specify.
I suggest for starters you read this to learn more about the GcmNetworkManager.
So to summarize:
All you really need to do is implement your network calls in a Service extending GcmTaskService and later whenever you need to perform such a network call you schedule a OneOffTask and everything else will be taken care of for you!
Of course you don't need to call each and every setter of the OneOffTask.Builder like I do above - I just did that to show you all the options you have. In most cases scheduling a task would just look like this:
mGcmNetworkManager.schedule(new OneoffTask.Builder()
.setService(MyTaskService.class)
.setTag(TASK_TAG)
.setExecutionWindow(0L, 300L)
.setPersisted(true)
.setExtras(bundle)
.build());
And if you put that in a helper method or even better create factory methods for all the different tasks you need to do than everything you were trying to do should just boil down to a few lines of code!
And by the way: Yes, an IntentService handles every Intent one after another sequentially in a single worker Thread. You can look at the relevant implementation here. It's actually very simple and quite straight forward.
All UI and Service methods are by default invoked on the same main thread. Unless you explicitly create threads or use AsyncTask there is no concurrency in an Android application per se.
This means that all intents, alarms, broad-casts are by default handled on the main thread.
Also note that doing I/O and/or network requests may be forbidden on the main thread (depending on Android version, see e.g. How to fix android.os.NetworkOnMainThreadException?).
Using AsyncTask or creating your own threads will bring you to concurrency problems but they are the same as with any multi-threaded programming, there is nothing special to Android there.
One more point to consider when doing concurrency is that background threads need to hold a WakeLock or the CPU may go to sleep.
Just some idea.
You may try to make use of serial executor for your file, therefore, only one thread can be execute at a time.
http://developer.android.com/reference/android/os/AsyncTask.html#SERIAL_EXECUTOR

keep service alive in android

I have created an Android service which basically does the following:
schedule a task, using the ScheduledThreadPoolExecutor.schedule() method
when the schedule time is reached, the task is executed and a new schedule is started
Thus, the service continuously has a timer in place (except during execution of the task); sometimes 2 (independent) timers are in place, depending on the result of the task. The service should be running all the time and executes different tasks from time to time.
All seems to work ok (at least when running with DDMS), but after a while (something like an hour without connecting the device via DDMS) the timer tasks are not executed anymore. The only way to get it working again is either stopping and starting the service again or by connecting the device with DDMS (using Eclipse); waking up the device only does not trigger this.
It looks like, Android sets the service in a kind of sleep mode (service is still running when looking at the Active Services on the device).
My question is: how do I prevent this behavior and keep the service working all the time?
I did some research and I found something which theoretically could give a solution, by acquiring a (PARTIAL_WAKE_LOCK) WakeLock in the service, but as far as I understand, using this solution, I have to acquire the lock at the onStartService() method and release it at onDestroy(), meaning that I keep the lock during the lifetime of the service (which is forever); I suspect a battery drainage using this method.
Is there another way to accomplish the same?
I have solved the problem, thanks to the replies above.
I switched from the ScheduledPoolThreaExecutor() to the AlarmManager. Together with the RTC_WAKEUP type all triggers are handled now.
I did not use the IntentService, because my service has to do things in parallel based on alarms (and IntentService implements a queued solution). The original service, which was staying alive all the time in the original implementation, is now only created whenever an alarm is triggered.
I also have the impression (but that is only a gut feeling, not based on real measurements, that this new implementation (where the service is created when needed and is not alive all the time (waiting on timer evens), is even better for battery life of the device.
How often to you need to execute, and what do you mean by running all the time? I guess that you don't mean be executing all the time?
I have a service that does this, and it works quite well:
It schedules an alarm with the alarm manager. Acquires a wakelock when the alarm is triggered, performs some work, and then schedules a new alarm before releasing the wake lock.
Use IntentService for your service implementation and register pending intents with AlarmManager to trigger those intents on the time basis you need.
I have used wake locks in an app before and I did not need to release them in the onDestroy(),
I literally had the following and it worked perfectly:
onClockListener{
acquire wakelock
method call
}
otherOnClickListener{
release wakelock
other method call
}
Not sure if it will help much but it definitely wont help if I don't post anything :)

Categories

Resources