My application makes its web service calls from an IntentService. Each Intent is effectively a web service call that needs to take place.
As you know, an IntentService queues Intents; so only 1 web service call will be taking place at any given time. This is actually desired behavior.
However, this does present a problem. Suppose my app queues up 5 Intents in this IntentService. Say the user ends up on a screen that maybe holds up the UI while some data is retrieved from a web service. If the Intent for this web service is put on the back of the queue, it could be a long while before the web service is called, holding the user up for an unacceptable amount of time.
Since I can't inject Intents to the front of an IntentService's queue (as far as I know), I've decided to create a second IntentService for calls that require immediate execution. Since I only want 1 call hitting my services at any given time, I've wrapped a mutex around the actual Http code. So, in this case, the Intent would execute right away (because it's in a different IntentService), but loop on the mutex until whatever call in the other IntentService is finished.
This works good for me; I'm fine with all of it.
Here is my question:
Theoretically, the new IntentService could queue up, too. Because of the application workflow, this is unlikely to happen, but it's theoretically possible. If this is the case, I'd like the new IntentService to finish before the original IntentService resumes again. My idea for doing this is locking/unlocking a new mutex in the create and destroy methods of the new IntentService. The same mutex will also be locked/unlocked at the beginning and end of the onHandleIntent method of the old IntentService. However, I'm concerned about what ramifications locking a mutex in the create of an IntentService will have, holding up its creation (presumably, super.create will be called before the lock). Will Intents still be able to queue up? Are there any other pitfalls to doing this?
Since I can't inject Intents to the front of an IntentService's queue (as far as I know)
Not with the standard implementation. However, IntentService is not a big class. You could clone it and replace the Handler-based system it uses today with a PriorityBlockingQueue.
Are there any other pitfalls to doing this?
Besides it scaring the crap out of me, in terms of possible deadlocks?
You might look at ReentrantReadWriteLock or something along those lines, instead of the Mutex pair. While technically yours is not a "read" vs. "write" scenario, you can think of "read" and "write" as simply being two priorities. There are ways to configure such a lock to favor "writes", so your 2nd IntentService would be the "write" and your 1st IntentService would be the "read".
But I'd really look to replace IntentService with a workalike that has the characteristics you seek, rather than trying to get two IntentServices to work together.
Related
There are several ways to connect to Service to Activity. I am only interested in local service and my LocalService will stand there untill user stops it(which also means end of app). I might know things wrong, if so please correct me.
On the reference page, it is stated that in order to use methods of local service directly, we should use ServiceConnection. After binding, we can have a reference to LocalService class, and we can use methods of this LocalService directly. AFAIK the methods we call using this reference run on main thread with relevant Activity.
The thing that confuses me, what if I use skeleton structure and access LocalService's methods by directly its static reference (ie. by LocalService.getInstance()). Well, I have already used it and did not face any problem, but still I am not sure which one is better, and why.
Thanks in advance. I might add additional info if requested.
edit:
In my previously mentioned solution, no activity is keeping a reference to the LocalService.
It is used to
start some LongRunningAsyncTasks(which are all halted and reference-nullified before service stop),
update the app Notification,
get getFilesDir(),
to keep an enum value (whose reference is not kept elsewhere, it is just used for comparison) in order to access from everywhere(not worthy of using SharedPreferences).
show some toasts
aware of static references of activities and services because they can be a reason of memory leak. if you don't want your service run in main process, then extract it into another process and work with service connection.
If you don't need any feedback from service, then just don't use connection and simply use startService() with several commands which will be executed in onStartCommand() method of the service.
If you need feedback from service, but not frequently, then use startService() and feedback from service with sendBroadcast() or through Handler class.
If you need feedback frequently (for example update slider of media player), then it's better to use service connection.
Remember that your service can be killed anytime without executing method onDestroy() and without any notification, that's why keeping static reference is not good idea.
It appears from what you are saying that you probably don't need a Service at all. Looks like you are not doing any long-standing task in your LocalService. If that's the case, you can as well use AsyncTask or Handlers and be done. The motivation to use a Service (Local or otherwise) is to do some long standing task inside it and not stall the main UI thread. If your tasks are not gonna take up too much time, then you don't need a Service.
The Service does run on the main thread by default. Unless it's an IntentService where a worker thread is created for you automatically and all tasks are queued and handled one at a time in this worker thread. Otherwise, it's your responsibility to create a separate thread for your service tasks.
So, first analyze if you really need a Service. If your task can quickly get executed, then don't bother having a Service even.
Hope that helps.
My application does a sync process every 30 seconds.
What I do is, send some data, and accordingly get a set of data, and update/insert into my local sqlite DB. Sometimes, I updated my GUI as a result of these operations.
I read in several posts that an asynctask can do this task perfectly, and in some other posts many people discouraged the use of asynctask, and told me to implement the intentService/broadcast receiver approach.
Which one is better? and when ?
There are multiple considerations that you must weigh in order to best decide how to approach your situation. Acording to the doc:
...an activity that initiates a long-running
operation might do well to start a service for that operation, rather
than simply spawn a thread — particularly if the operation will likely
outlast the activity. Examples of this are playing music in the
background and uploading a picture taken by the camera to a web site.
Using a service guarantees that the operation will have at least
"service process" priority, regardless of what happens to the
activity.
A Service is a part of your Application that has no UI. It may be called by a UI(Activity) to be started, or may be started by any other component of your Application. When developing, you have the freedom to place it on a different thread, or even run it in a different Task or Process. This allows you to ultimately separate it from your UI. Additionally, you may start the Service to run independently (startService) or bind your activity to it (bindService) depending upon your needs. By using custom Handlers, you can set callbacks to update the UI with your progress. A Service does not necessarily end if a User changes Activities, but may be ended at ANY time by the OS.
A AsyncTask is always instantiated from the UI thread. It only allows specific callbacks, but simplifies the process of multi-threading for the purposes of relatively short transactions (as compared to dedicated separate threaded services) that are inherently tied to actions performed by an Activity. Whenever a User changes Activities, the AsyncTask is put on "pause" and may even die because there is no UI thread for your Activity any longer.
The problem with the AsyncTask is if the user goes to another Activity you can't transfer that object to the other Activity so it dies. There are tricks you can play when say the user rotates the screen or something like that, but that doesn't extend to general purpose destruction. AsyncTask can randomly die. On the other hand you can definitely communicate between Service and Activity, but it's tricky to do it right.
So, depending on your scenario, you have to take a design decision.
If you need to update the UI then AsyncTask will be a better fit, however if you need it to update in the background when the app is not running then IntentService would be better and you will need to come up with a way to update the UI from your IntentService
This is more of an opinion based question so I would not expect one definite answer. Its a per-app basis question
Looking at the source code for the stock Calendar app, Google uses an IntentService to do the content provider operations for the database. Is there an advantage to using an IntentService rather than a AsyncQueryHandler?
I thought that since a Handler is tied to the UI, if the activity gets paused or stopped, the Handler would also get paused. However, this doesn't seem to be the case: I created a simple content provider and AsyncQueryHandler that do nothing but run through a long for loop. When I launch other apps or kill the activity, the for loop still runs.
So is the advantage of using an IntentService for asynchronous CRUD operations that the service (being a service) has less of a chance of getting killed?
Update: Part of my confusion is how a handler relates to an activity's lifecycle. From my experiment, it seems that it's independent.
Also, for those not familiar with the stock Calendar app source code, the way it works is that to do a CRUD, it adds the operation to a queue along with a reference to a handler. Then it starts the intent service which pops the queue and does the CRUD. When it's finished, it invokes the handler via Message.sendToTarget().
So what does that extra complexity buy us?
I am stuck with the same confusion. What I found is the IntentService will get killed with the activity. This also means that it will get killed on Orientation change. While an AsyncQueryHandler will keep on running(as you found out). In my use case I am updating my UI first without waiting for the database to update. So I think I am gonna opt for AsyncQueryHandler.
I don't know much about Intent Service(never used it) but as it is sending messages It might be useful when you need something from database to show on the UI thread..so that you know when the database was updated.
I'm developing an app with a service that forwards calls to a web-service, and a few activities that place those calls. The activities need to process the results of those calls. For example, I have a writeComment method on the service, that accesses the web-service and returns some information about the newly written comment.
Right now I let the Activity take care of all the threading. The Activity binds the service, and then uses an AsyncTask that calls the bound service's writeComment method.
All works well as long as the Activity isn't stopped while the AsyncTask is running. If it does (easily happens when flipping the phone), the AsyncTask dies a violent death when trying to update the UI in onPostExecute. I'm not entirely sure how to fix this - I do need to let the user know the server has been updated.
If I go the other way around, and register a callback with the Service, I'm still a bit stump, because I need to notify the Service the Activity has changed - I need to tell it not to notify me in the first Activity's onDestory, and reregister in the second Activity's onCreate. And I need to handle the case where the asynchronous task completes after onDestroy and before onCreate.
What is considered Best Practice in this case?
Thanks,
Itay.
My intuition tells me to let the service handle the threading. Services are far less transient (although still transient to some degree) than activities and therefore you'll have less issues of threads trying to interact with a Context (be it an Activity or a Service) that's no longer there. Have you looked at the IntentService class? It handles a lot of the threading for you.
In my app, I have a long-running service and Activities that need to render data in the service. The service also pings the Activities when there is a change but the Activity can also query the service. The way I approached this was two-fold.
Firstly, I bind my activity to the Service in order to send messages from Activity to service.
Secondly, the Service sends notifications with Broadcasts and the Activity listens for those broadcasts. I set that up in the Activity onResume and tear it down in the onPause. I think this is the part that you're missing.
I have a requirement, whereby when a user clicks a button, then an object needs to be observed. When the user clicks that button again, the observation stops.
My initial thought is to have the button bound to a method in the activity using the onClick="myMethod" in the layout file.
When this method is invoke it will call startService() which starts observing the object. By this I mean it registers the service as an observer.
When the button is clicked for a second time, it calls the stopService() method which un-registers the service as an observer.
My thoughts for using a service is so the observation; and subsequent actioning is taken off the UI thread. Is this a reasonable approach or is there something in the Android SDK that could do this easier?
My thoughts for using a service is so the observation; and subsequent actioning is taken off the UI thread.
Only if you fork your own thread, and only if the "observation" supports alternative threads. Services are in the "background" from a UI standpoint (they do not draw on the screen directly), but they are not in the "background" from a threading standpoint by default.
Is this a reasonable approach or is there something in the Android SDK that could do this easier?
That is impossible to answer given what you have written above. You seem to think the button is important -- probably, it's not. What probably is important is what this "object" is that you are "observing"...and you didn't say what it is.
If your service will reliably unregister itself in stopService(), you should not run into garbage collection issues with this approach. However, threading with respect to the observer/observable pattern usually is the responsibility of the observable -- in this case, the mysterious "object".
I agree with Murphy however a small point i think i should give you:
1. what are you doing when the activity is destroyed ? paused ?
2. if the object u are observing is generating events that you need to observe you have to think what happens to them in all situations, if the observer object dies with the activity, i think u are better off with async task or local thread, in any case you will also have to discover that the activity was destroyed in your service in order to GC the observed object or kill the service too in the Activities onDestroy.