I know an IntentService itself runs on a different thread.
Also that it execute the onHandleIntent() and stops when that method is done.
my question is: are there any consequences for creating my own custom Thread inside the intent service?
I know it can be done in a Service but I want to know if thats a wrong way of using IntentService
for a bit more information what I need to do is to send lots of HTTP requests.
What im about to do is save on a DB the request strings, and run intent service that execute them.
That's why I use IntentService, the requests might take time and I want the service to shut down once the table containing the requests is empty.
I thought i might increase the speed of this service by adding my own threads to it as I will be running lets say, 5 threads each time.
EDIT:
This is the code I thought to do, I guess it will clear things about what im trying to do and if its possible.
protected void onHandleIntent(Intent intent) {
helper = new DBHelper(getApplicationContext());
File file;
//checks if the DB requests exists
while(helper.requestsExists()){
ArrayList<String> requestArr = helper.getRequestsToExcute(5);
if(!requestArr.isEmpty()){
//execute them and delete the DB entry
for(int i=0;i<requestArr.size();i++){
file = new File(requestArr.get(i));
new MyThread(file).start();// the DB entry is delete withing the thread
}
}
}
}
so this service will run as long as it got any DB entries on my SQLite db, after it will finish executing all of them it will stop.
is it ok or should i use Service for it?
As you have explained, the onHandleIntent is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic.
Why do you want to create a separate thread unless you want to handle multiple requests coming in and handle them in parallel ?
So, if you handle the action that you are suggesting in the onHandleIntent it will hold up other requests to the same IntentService, but it will not hold up anything else.
This answer might help you - start async task from onhandleintent
Related
I'm writing a webserver with spring(mvc,data,security) which is serving tasks to physical devices(device count is around 100).
Device doesn't have query implementation inside. For example to execute some task u need write something like this:
Device driver = new DeviceDriver();
driver.setSettings(settingsJson);
driver.open(); // noone else can't connect to this device, open() can take up to 1 second
driver.setTask(taskJson);
driver.processTask(); // each task takes a few seconds to execute
String results = driver.getResults();
driver.close();
I'm not really an expert in designing architecture, so for now implemented webserver like this:
TaskController(#RestController) - processing incoming Post requests with tasks and persisting them to database.
DeviceService(#Service) - has init method, which gets list of devices from DB and creates/starts one worker per device. It passes taskRepository to each worker, so worker inside can save results of tasks.
Worker - extends Thread, it gets next task from database with certain period(via loop with sleep). When task executed worker saves result to db and updates status of task.
Does this approach makes any sense? Maybe there is better way to do this using spring components instead of Thread.
I would not create workers for each device (client). Because your controller will be able to serve concurrent requests being deployed on a thread-per-request based server. Additionally, this is not scalable at all- what if there is a new device on-boarded? You need to make changes on the database, restart the service with the current design!!
If you need device specific actions, you can just pass that on the request parameters from the device client. Therefore, there is no need to keep a predefined set of workers.
So, the design looks good except the worker set.
Use the #Scheduled annotation on your functions to build something like cron
I have a number of AsyncTask instances that are downloading some different content from the server. They run on executor:
final GetStationsTask getStationsTask = new GetStationsTask();
getStationsTask
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, URL_STATIONS);
Currently I have 3 subclasses of AsyncTask, but this number will not stay the same. I am also implementing some kind of retrying for tasks that were not completed for different reasons, and I would like to download everything from the beginning, if at least one of the tasks was not finished correctly (the data was not received):
// mHandler = new Handler(); // an instance variable
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (!allDataSet()) {
// here I want to cancel the tasks that are still running
// and rerun all of them
}
}
}, 30000); // I give all the tasks 30 seconds to complete
For that I suppose I need to know which tasks are currently running, which tasks have finished correctly and which ones were cancelled, because if all the tasks get restarted, I need to cancel the running ones first to prevent the data from being received multiple times. Any ideas how to solve it?
Override the base AsyncTask, and use that as your base class for all AsyncTasks. Have the overriden task have a static list of running, cancelled and finished tasks. Then add each task to the relevant list in the base class methods.
You can keep a list of AsyncTasks being currently executed in some singleton class, ie. Application extended one.:
List<AsyncTask<String, String, String>> downloadsAsycs = new ArrayList<AsyncTask<String, String, String>>();
inside of your asynctask's onPostExecute remove it from list using downloadsAsycs.remove(this). Remember to either synchronize on using this list, or always modify/read it on UI thread, ie. inside Handler from mainlooper or in onPreExecute/onPostExecute. You can check status of your async task using AsyncTask.getStatus(). After a while it starts getting complicated.
You could also switch from AsyncTask to Executors.newFixedThreadPool and ExecutorService.invokeAll. You could invoke all your tasks and have returned Future for all of them which allow to control them. You could even use Future.get with timeout on some back thread (even asynctask.doInBackground) to 30s, and after this time use Future.cancel if operation timed out.
Since the number of tasks is unknown, but they need to communicate in some way.
I would suggest to create 2 classes:
YourTask class - all needed tasks would be it's instances
TaskMediator - which manage communication as Mediator Design Pattern
So every time one task (YourTask) created it register it's self
to predefined class (TaskMediator) which manage their communication.
That way you get looser coupling between their objects,
but still keeps one communication channel
*By the way your TaskMediator can be Singleton as suggested by Marcin Jedrzejewski
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
In my application I need, basically, two tasks performed in the background. One is sync some data with a php server, sending values and updating the local database with the answer periodically and the other is download files requested by the main thread from the server,notifying the UI when the download finish.
I only want do those things while the app is in foreground. And if the users opens another app, finish the current transactions and stop consuming resources.
At this point I'm a little lost about how to implement that. I have never used Services and I really dont know if a service is a valid solution, due to the service is used when you want your code still running when the app goes to background.
Other solution I've thought is to implement some kind of Handler that periodically (20 minutes for example) launches a thread for sync with the server. Lauching a thread also when a download is requested and sending a broadcast at the end.
What about that solution? Is valid? If yes, how can I detect when the app (not an activity) stops beeing at foreground in order to cancell the handler's posts?
Thanks in advance
If you choose the service I recommend you to use an IntentService http://developer.android.com/reference/android/app/IntentService.html
When you implement onHandleIntent you can have a loop that waits for the amount of time you want it to sleep, after it wakes up it can perform the task that you want.
#Override
protected void onHandleIntent(Intent intent) {
while(true) {
yourBackgroundTask();
// Sleep
try {
wait(WAIT_TIME);
} catch (Exception e) {
Log.i(TAG, e.getMessage());
break;
}
}
}
I have a method that will be used to send out email. i want to lock this method so only one thread can accses it per time and the rest pool up concurrently. should i synchronized the method or use spring #transactional PROPAGATION_REQUIRED ?
in my service layer
//each time use new thread to send out email
public void sendThroughSMTP(List<String> emails,String subject,String content){
//each time will open and sent through port 25. dont u think this will caused too many threads spawned?
BlastEmailThread blastEmailThread = new BlastEmailThread(emails,subject,content);
blastEmailThread.start();
}
Why not make the method thread-safe by not using any instance level things?
However, I don't see how Spring's Transaction Management fits here. I mean Spring provides few transaction managers, i.e. DataSourceTransactionManager, JtaTransactionManager, HibernateTransactionManager all this is about database persistence. What will you configure for this email send out?
I believe, first you should show us why you worry about the thread-safety in the first place. Most probably you would like to show us some relevant code snippet or something. Then we might be able to suggest you something.
[Addendum]
When you are spawning a thread for every call to that method and not using anything from the state, then why you want to make the method synchronized. Making the method synchronized will not limit the number of threads in any way. There might be chance that before starting a new thread, previous thread might have finished the work, because of synchronization. The process of spawning a thread might go slower.
However, you should go with this until you find out that there are really many threads running and you are going out of memory. And if you really want to tackle that before time, then you should choose some blocking mechanism, something like Semaphore.
I'm not sure if it answers your question, but instead of creating a new thread for every mail and calling start on it you could have an Executor or ExecutorService as a member of your class, as an implementation you could use a ThreadPoolExecutor with a pool size of 1. Your sendMail method would then submit Runnables to the executor.
Another possibility would be to use JMS queues and put the email sending code in a Message Driven Bean (or through Spring JMS). You can then use your app server to control how many concurrent instances of your MDB will be used and throttle the outgoing emails that way.
in Sping 3.0 you can use #Async annotation to do task execution, so your method will be executed later and the method is returned directly without waiting for email to be sent.
#Async
public void sendThroughSMTP(List<String> emails,String subject,String content){
//Send emails here, you can directly send lots of email
}
then in application context you specify and don't forget to add xmlns for task schema.
If you want to delay the execution for certain amount of time, you may use #Scheduled annotation to your method.
Further tutorial about #Async and #Scheduled can be found here :
http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
Make your service a singleton and add synchronized to your method.
Spring #Transactional is not quite correct used in your case. The best bet is using synchorized method and add some thread pooling if your method called by hundreds time. But i guess you dont need thread pool here.
If you use thread to send blast email, then what's point synchronizing the method? if one process call your method and send email, other process will call you method even the first sending email process not yet finish.
If you intent to throttle the email sending process, you need to condider a queue (collection) and protect the collection with synchronize block. Create another process to monitor that queue, if there is one item in queue, pop it and send blast email, then wait until sending email process finish and check again the queue, if there is any item, continue to sending email process. If no item in the queue, make the monitor thread sleep for some chunk of time, then if sleep time is finish check the queue again.