Is it possible to IntentServices to be called out of order? - android

I have 2 calls to startService made on the same thread, but apparently these calls are received out of order in my IntentService.
Our client says that the feature works on some devices and no on others, so I'm guessing this out of order could be the case.
I know that IntentService has a FIFO way to execute the Intents. So, once the intent arrives, the order is guaranteed. My question is that could be possible that one startService was delayed and the other goes first. Does anyone have any idea how startService works internally?
The code goes more or less like this
(... some logic...)
callService(param1)
(... more logic...)
callService(param2)

Related

Can i do all my work in a broadcastreceiver instead of spinning off a service?

I understand that it is a standard pattern for listening for events using a BroadcastReciever and from within the onReceive() method to spin off a Service to do the work related to that event.
My question is that is there anything stopping me from performing all my work (let's saying some database transactions) in the receiver itself? Sometimes, the work is so small that it might not mandate the creation of a service. Is this legit?
Yes, if your work is supposed to occur on the main thread and the work is relatively quick. You get IIRC about 2 seconds before you'll get an ANR crash. If you only have a few milliseconds of work there's no reason to start a service.

Overlap in the responsibilities of BroadcastReceiver and IntentService

Is it correct that there's some overlap in the responsibilities of BroadcastReceiver and IntentService? By that, I mean that it would be redundant to set up a BroadcastReceiver that triggers an IntentService that performs some task that needs to be done. Since both respond to intents it's simpler to have just the IntentService respond directly to the intent without BroadcastReceiver serving as an intermediary.
Is this interpretation correct? Is it always correct? If not, please give an example of when it's incorrect.
Thanks much!
I mean that it would be redundant to set up a BroadcastReceiver that triggers an IntentService that performs some task that needs to be done
Not only is that not necessarily redundant, it is a very common pattern.
Is this interpretation correct?
No.
please give an examples of when it's incorrect.
Either an Intent is used with sendBroadcast() or with startService(). If an Intent is used with sendBroadcast(), it is not possible for a service to respond to it directly. Similarly, if an Intent is used with startService(), it is not possible for a receiver to respond to it directly. So, in cases where somebody else wrote the code to use the Intent, you have to match up with how they used it. You cannot unilaterally "change the channel" that the Intent is used on.
Beyond that, onReceive() of a BroadcastReceiver is always called on the main application thread. You do not want to take any meaningful amount of time here, as it will freeze your UI if your UI happens to be in the foreground. And, once onReceive() returns, a manifest-registered receiver's instance is discarded, and your process may be terminated shortly thereafter. Hence, it is not safe for a BroadcastReceiver to fork its own background thread, as Android will ignore that thread and terminate your process. A common pattern for responding to system-sent broadcasts is to use a BroadcastReceiver, then have it delegate the work to an IntentService. In one fell swoop, you solve both problems:
IntentService does its heavy lifting in onHandleIntent(), called on a background thread
because it is a Service, having it running while doing that work will signal to the OS to let your process live a little while longer
Now, if you are the one creating the Intent and you are the one dispatching that Intent and you are the one consuming that Intent, and you want to have your code use startService() directly to invoke an IntentService, that is perfectly fine.

are startService() Intents serialized?

a) if my code calls startService() twice, will the Intents be processeced in the order I called them, or might they get switched randomly?
b) will the first run through onStartCommand() complete before the second call starts, or might they run in parallel?
I have read the android services guide and the reference. While they clearly show how the IntentService worker threads are serialized, I've found little information on how the Intents are delivered and processed.
if my code calls startService() twice, will the Intents be processeced in the order I called them, or might they get switched randomly?
The behavior for Service in this regard is undocumented, last I checked. However, they should be called in the order they were issued, based on what seems to happen in practice.
will the first run through onStartCommand() complete before the second call starts, or might they run in parallel?
That is up to you. By default, onStartCommand() on a Service is called on the main application thread, and therefore only one command is processed at a time. If you choose to fork threads from onStartCommand() to process commands, those threads may run in parallel.
While they clearly show how the IntentService worker threads are serialized, I've found little information on how the Intents are delivered and processed.
IntentService maintains its own thread. You implement onHandleIntent() instead of (or possibly in addition to) onStartCommand(). Since there is only one thread, only one onHandleIntent() will be executed at a time.

Better understanding Services

In the app I am working on, I have an AlarmManager that starts a Service at specified times and intervals. The Service uses some data I send in the Intent to read/write the SQLite database, make a Notification and send an SMS. I've had a problem that when the device goes into "deep sleep" and I use the device again, I get a force close with a NullPointerException on the Intent in the Service. As I've done some research, I've had several questions about how a Service works that I haven't been able to answer:
1) I realized that I was using the deprecated onStart method for a Service. I am going to switch to onStartCommand with START_REDELIVER_INTENT flag (think this was the null exception I was getting because the Service was trying to restart with the old onStart and not getting the original Intent). My question is this: Should I put the work the Service does in the onStartCommand or in onCreate? Is there any functional difference?
2) Considering what I am doing in my Service, is this enough work to put in its own Thread?
3) Do I need to specifically call stopSelf? If so, where is the best place to call it?
4) This one is more ambiguous: To my knowledge, I had canceled all of the alarms registered and after deep sleep, I still got the null exception for a Service. Is there any reason the Service would still get run even though I never triggered it with an alarm?
Please ask any clarifying question if necessary. I haven't posted code because most of it is generic for starting and consuming a Service, but if you want to have a peek, let me know. Thanks.
You should use IntentService instead of regular old Service. It does all its work in a background thread and stops itself automatically when it runs out of work.

Holding up IntentService creation

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.

Categories

Resources