Start Service on Multiple Activities While Passing Data on Each Activity [duplicate] - android

This question already has an answer here:
Multiple activities binding to a service
(1 answer)
Closed 7 years ago.
I want to create this service to work with multiple activities. I mean each activity will be able to send a data to this service and get a data from it.

Basically, i would suggest that you start the service in application class and send broadcast to service whenever its needed to send any data to service.But make sure the service is running.

When you create a Service you should override the onStartCommand() method so if you closely look at the signature below, this is where you receive the intent object which is passed to it:
public int onStartCommand(Intent intent, int flags, int startId)
So from an activity you will create the intent object to start service and then you place your data inside the intent object for example you want to pass a userID from Activity to Service:
Intent serviceIntent = new Intent(YourService.class.getName())
serviceIntent.putExtra("UserID", "123456");
context.startService(serviceIntent);
When the service is started its onStartCommand() method will be called so in this method you can retrieve the value (UserID) from the intent object for example
public int onStartCommand (Intent intent, int flags, int startId){
String userID = intent.getStringExtra("UserID");
return START_STICKY;
}
Note: the above answer specifies to get an Intent with getIntent() method which is not correct in context of a service

In this scenario, you should consider using IntentService. IntentService is a special kind, which handles a queue of work, sent through Intents.
When the first activity calls startService(), the service is started and begins its work. Consequent calls to startService, will queue them and results in the works being processed one after another, until the last sent intent is done, and then service will shutdown it self. It's pretty straightforward to use and takes care of the heavy lifting and all the boilerplate code you should write.
For further study, you can take a look at this .

Related

Service: onCreate called again after restarting app

I pass through the data to be processed via intent:
Intent intent = new Intent(getActivity(), LocationService.class);
intent.putExtra....
...
startService(intent);
onCreate method called once while browsing app, but when I closed app and removed from task list(I checked, service is still runing), then I start app again - Service onCreate called again.
From the doc:
If the service is not already running, the system first calls
onCreate(), then calls onStartCommand().
Update:
What constant are you returning at the end of your onStartCommand
method?
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
Pleasee post the type of service and startmode
LocationService extends Service
Yes the android doc is correct , it will call the service's onCreate() only first time it is created , and then delivers all the intents to onStartCommand() .
But I've have came across these two google groups having the discussion that might be helpful to you
https://groups.google.com/forum/#!topic/android-developers/LtmA9xbrD5A
and https://groups.google.com/forum/#!topic/android-developers/H-DSQ4-tiac
Not much of a help , but might be of some interest .
Enjoy !

How to stop one IntentService while there are many IntentService are running

I have a listview contains many songs. Each time a song is clicked, I call an IntentService to download this song by sequence.
But sometimes I want cancel a download (for example: the 5th). It means I need to stop the 5th running IntentService. I attempt to stop it by call stopService() but it doesn't work.
Can anyone tell me a good way to stop IntentService? Thanks so much for your help.
There is only one running IntentService, per <service> element in your manifest. If you call startService() six times, at most one IntentService will be running. Commands will queue up and be processed one at a time by onHandleIntent(), if the IntentService is processing a command when another command is sent.
In your case, since you cannot readily cancel an outstanding command with IntentService, you will probably need to create your own version of IntentService, where you create your own Service subclass with its own work queue, one where you have the ability to cancel commands that are not yet running.
I had the same problem while downloading using intentservices.
In my app, each download has its own notification, and when clicking on it I want to stop the download.
I solved it by overriding the onStartCommand() method (called when a new intent arrives).
When I wanted to close one download, I started a new intent with an extra called "stopid":
Intent stopIntent = new Intent(DialogActivity.this,DownloadIntentService.class);
stopIntent.putExtra("stopid", id);
startService(stopIntent);
The onStartCommand() method looks like this:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int id = intent.getExtras().getInt("stopid");
if(id!=0) {
stopList.add(id);
}
return super.onStartCommand(intent, flags, startId);
}
For normal intents, just put the id of your download in your intent as an extra.
While doing the download in the onHandle() method, check often if the stopList contains the id of your current download intent. If it does, stop downloading and remove the id from the stopList.

IntentService not firing

My application synchronizes data with a remote database via web service calls. I make these calls in an IntentService so they can run in the background (I call it SyncService).
The code to launch my IntentService looks like so:
Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);
// place additional values in intent
intent.putExtra("data_type", SyncService.ITEM_TRACKING);
intent.putExtra("user_id", intUserId);
// call SyncService
appContext.startService(intent);
This, normally, looks great. However, one of my friends, who is also a user of my app, often tells me his data doesn't sync and get displayed on our website. His device happened to be displaying the symptoms while I was around. I plugged his device into my computer and here is what I found:
The code to launch SyncService (ie: the code above) was hit.
I had a breakpoint inside the onHandleIntent method of my IntentService and it never gets hit.
I checked his device's list of running services and SyncService was there and running. Interestingly, it had been running for about 20 minutes. I was under the impression that IntentService killed itself when it was all out of Intents to process.
I force stopped the SyncService (not the app) and, all of the sudden, onHandleIntent started getting hit over and over. It was like all the Intents were queued up somewhere on the device and were just now getting thrown at the SyncService.
Does anyone have any ideas as to what may be the problem? Do you think it's an issue with my app? With Android?
Again, I am handing a message to Android saying, "Start this IntentService or send the message to the already running IntentService." At that point, I have no control. The message never gets to the IntentService. Once I force quit the app, the messages get sent to the IntentService and it does its job.
UPDATE: I think this code is fine, but I'll put it up since a lot of you may want to see it.
Every Intent that comes in to the IntentService has an Extra denoting what "type" of call is to me made (ie: do I call this web service or that web service, etc). When an Intent comes in to the IntentService, I check the "type" and, if there is already an Intent in the queue for that type, I add an Extra to it called "skip" so, when it is reached, I don't execute the search (basically the IntentService can build up lots of Intents and it makes no sense to call this web service when this webservice was called 20 seconds ago). It basically protects the app from spamming the website.
It is important to note that none of this code is hit anyway (once the problem starts occurring). onStartCommand does not get called until the app is killed
#Override
public int onStartCommand (Intent intent, int flags, int startId) {
// here be dragons
// overriding this method and adding your own code is dangerous. i've wrapped
// my code in a try/catch because it is essential that the super method be called
// every time this method is entered. any errors in my code should not prevent this
// or the app will explode.
try {
if (flags == 0 && intent != null && intent.hasExtra("data_type")) {
Integer intDataType = intent.getExtras().getInt("data_type");
if (!mCurrentTypes.containsKey(intDataType)
|| !mCurrentTypes.get(intDataType)) {
mCurrentTypes.put(intDataType, true); // put this type in the list and move on
}
else {
intent.putExtra("skip", true); // mark this Intent to be skipped
}
}
}
catch (Exception e) {
// Log.e("Error onStartCommand", "error: " + e);
}
return super.onStartCommand(intent, flags, startId);
}
private void processIntent(Intent intent) {
// do stuff if no "skip" Extra
mCurrentTypes.put(intDataType, false);
}
There is definitly something that keeps your service running on your friend's device. If so all subsequent call to this intent service are queued until the current one finishes. If it doesn't finish then you will get what you have : next services won't start.
You should double check that :
you give proper timeouts to nework operations
you give proper timeouts to nework connections operations
there is no race condition between threads.
you log any exception that can occur inside the service, you don't wanna loose that kind of information.
Afterwards, if you think everything is green : just log what the service does and use some bug reporting mechanism to get it automatically sent from your friends device. A simple solution could be to use bugsense or equivalent.
Next, put in place some kind of watchdog : a thread that will go on running until your service stops (you just tell your thread to stop when service is stopped). The thread will have to stop your service after some time limit has been passed.
This watchdog thread could be put inside the service itself, or outside, although this may be more complex to put in place.
This answer suggests a solution that worked for me in similar situations. It doesn't fix your current code but suggests another, perhaps simpler (and easier to debug) option:
Add a BroadcastReceiver to your calling Activity that listens for SUCCESS Intents from the IntentService.
In your calling Activity, include the logic for when to start the IntentService (and don't include it in the IntentService). The logic is:
Call startService() and set a flag in the calling Activity to CANNOT_CALL.
If the Activity's BroadcastReceiver has not received a SUCCESS broadcast from the IntentService, then startService() can not be called again.
When the Activity does receive a SUCCESS intent, set the flag to CAN_CALL, and startService() can be called when the timer hits again.
In your IntentService, write your onStartCommand() like so:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
In you IntentService, when you've received, parsed and stores the web service response, call sendBroadcast() with an Intent with custom action SUCCESS.
This logic is just an outline and has to be fine-tuned for error messages from the web service that have to be broadcast from IntentService to the listening Activity.
Hope this helps.
It seems to me that setting a set of flags to your Intent may solve the problem.
Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);
// This way
intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK|Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
You can make your Service start as fresh using the above flag in a fresh task.
One more comment. It's not an answer for your question. However, it may affect overall behavior of a service.
You do following:
return super.onStartCommand(intent, flags, startId);
Internally Service.onStartCommand() looks like following
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
mStartCompatibility is false if your app target SDK API 7 or later (which is most likely a case).
So, as result your service will be started as START_STICKY.
Here is piece from documentation:
For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them. See the linked documentation for more detail on the semantics.
Base on what you have described, I recommend to replace "return super.onStartCommand(intent, flags, startId);" to "return START_NOT_STICKY;"

Android : How to differentiate commands used for StartSevice()

I have a questions here. I wanted to communicate to my service from my broadcast receiver. So I used the StartSevice(intent) method. In the service side the OnStartCommand() is called everytime I called StartService(). I just need to know how can i recognize in the onStartCommand() from where it is called from?
I hope I am clear in my question. If not please let me clarify...
You can't really check where you're called from, but you can do something a little bit related. You can specify certain tags in the Intent that you pass to the onStartCommand(). Notice that onStartCommand() takes an intent as its argument, this will be the intent that you sent. Whenever you send an intent to start the service from your broadcast receiver, you can specify certain "extras" in your intent and then use get those in your service.
http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int)
By the way, the use case you give seems to line up more with an IntentService than a regular service. This is a service which does what you're doing already: it sits there and waits for intents to be fired at it, and then reacts accordingly:
http://developer.android.com/reference/android/app/IntentService.html
In the onStartCommand method, the Intent you used to start service is passed as an argument.
onStartCommand(Intent intent, int flags, int startId)
So you can add Extras to intent to distinct where from it is called.
intent.putExtra("From", "MainScreen");

stopService(intent_with_extras) - how do you read those extras from within the service to stop?

I have a Service that can be stopped in multiple ways. Whenever I call stopService(Intent), I pass an intent with some extras. How do you retrieve those extras?
Thanks.
You need to override onStartCommand() in your Service this is how you get a reference to the incoming intent from startService.
In this case you would have a special action in your intent to tell the service to stop itself. You add extras to this intend which can be read in the onStartCommand() method.
Sample Code
public class MyService extends Service {
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
final String yourExtra = intent.getStringExtra(YOUR_EXTRA_ID);
// now you can e.g. call the stopSelf() method but have the extra information
}
}
Explanation
Every time you call context.startService(Intent) onStartCommand() will be called. If the service is already running a new service isn't created but onStartCommand is still called. This is how you can get a new intent with extras to a running service.
I found that the extras are not passed with the intent when stopService is called. As a workaround, simply call startService(Intent) and stopService(Intent) right after one another.
Example code from Activity:
Intent j = new Intent(SocketToYa.this, AccelerometerDataSocket.class);
j.putExtra("com.christophergrabowski.sockettoya.DestroyService", true);
startService(j);
stopService(j);
In Service.onStartCommand,
intent.hasExtra("com.christophergrabowski.sockettoya.DestroyService")
will evaluate to true, and you will destroy your service the way intended by the API (i.e., by calling stopService, which will in turn call OnDestroy after onStartCommand is called).
My suggetion is that use static member in class that extends Activity for passing information to service & it in service as normal static member access in outside class
Please don't do this unless you have no other option. You should try to use the mechanisms built into the framework for passing data, and not use public static fields unless there is no other choice. Read the Service documentation for examples.
Are you able to use an Intent with a "shutdown" action with Context.startService()?
That is, send an Intent with a shutdown action and extras to Service.onStartCommand(), decide how to shutdown based on the extras, then use Service.stopSelf() to stop the service.
I agree this isn't a great solution, since it potentially starts the service in order to shut it down. I would still like to hear of the "correct" way (if one exists) of doing this with Context.stopService().
You can not write
getIntent()
method in a class extending Service. So I think using getExtra() won't work.
My suggetion is that use static member in class that extends Activity for passing information to service & it in service as normal static member access in outside class i.e.
Classname.yourobject
.
see this link for other option
http://developer.android.com/resources/faq/framework.html#3

Categories

Resources