I've inherited a project and I don't understand how to either get a response, or set a callback from the following code:
startService(new Intent(this, VenueUpdateService.class));
At the moment the application continues even if the VenueUpdateService fails. I want to change it so that the application waits for a success/fail from VenueUpdateService.
I get a response within the VenueUpdateService class about success/fail. But how do I pass this back to the activity that started the service?
Thanks,
James.
What you're asking to do seems kind of strange to me. A Service will always succeed in being started if you call startService. It's not as if startService is some risky behavior that needs be wrapped in a try/call block.
But I suppose your Activity could register a BroadcastReceiver that receives a broadcast sent from the service in onStartCommand.
Or maybe you're looking to bind to the service, in which case you'll know when you're bound. see here
What I did was change the IntentService to an AsyncTask.
I basically wanted to stop the user interacting with the app while the VenueUpdateService did it's thing as it had to succeed at least once before the user could continue using the app.
So now I have:
VenueUpdateTask task = new VenueUpdateTask();
task.execute(response);
Within that class I show a progress dialog, do update venues.
Related
I develop a StepCounter application with Xamarin.Android.
What do I have for now:
1) In MainActivity in OnCreate() I call
StartService(new Intent(this, typeof(MyService)));
Then in OnStart() I call BindService(serviceIntent, MyServiceConnection, Bind.AutoCreate);
2) That gives me a nice service which is 1) foreground 2) both StartService and BindService 3) returns StartCommandResult.Sticky in OnStartCommand()
3) In MyService I register MainActivity as a listener for every detected step. I use Interface as suggested here and the UI in MainActivity updates in real time, everything works perfect.
But there is a problem.
When I swipe MainActivity from recent tasks my app supposed to shut down/finish/going off and so it does.
But MyService is STICKY so it starts again and the user can see a notification in status bar. That's exactly what I want. Sticky undying service.
And than first scenario: user presses the notification -> that creates an activity -> OnStart() provides binding to MyService again -> works ok.
Second scenario: user does not press the notification -> no activity has been created (it's the only service) -> user makes some steps -> application fails.
I don't know how to handle this second kind of behavior.
Maybe that is because I register MainActivity as a listener? And if I destroy it there is nothing to update My service? In OnStop() I call UnbindService(MyService); and I expect that MyService can work even without activity. But obviously, I do something wrong.
Any help is appreciated.
UPD: Find the solution, see my answer below.
Thanks for help everyone! The solution was quite simple. In MyService I register MainActivity as a listener using interface. So it's not surprising that destroying activity causes failure - there is nothing to update anymore.
Solution is check for null before calling this.listener.UpdateUI();
I understood your situation and somehow also got the idea that you want to achieve.
In the service class the return type you must be using is START_STICKY and I suggest you to use START_NOT_STICKY.
Both have their own significance and use. Further how to use the return type you can go through this answer
Im still a bit new to the Android Service Class. I know you need to start the service from your application with startService(intent), however my problem is my service has methods inside it. I need to start the service with an intent and then create an object of that class in my Activity so I can call methods of the service. The problem is when I do this I create one instance of the service when I start it with an intent and another instance of the service when I create an object of the class in my activity. This means any data passed to the service from startService(intent) is not there when I create the object of the service. Any ways around this or am I just totally misusing the service class? I can give some code but its basically this:
//Create Object of ControlPanel service class.
ControlPanel cPanel = new ControlPanel();
//Create intent for starting ControlPanel service class
Intent controlPanel = new Intent(this, cPanel.getClass());
//Start Service
startService(controlPanel);
I'd say you are misusing the class :-).
Calling startService() multiple times does not result in starting multiple service.
From the doc:
Request that a given application service be started. The Intent can either contain the complete class name of a specific service implementation to start, or an abstract definition through the action and other fields of the kind of service to start. If this service is not already running, it will be instantiated and started (creating a process for it if needed); if it is running then it remains running.
You should override onStartCommand() as well. The first startService call starts the service if it has not been started yet. In any case onStartCommand will intercept any further startService calls and the intent you want to send to it.
Any ways around this or am I just totally misusing the service class?
You are totally misusing the Service class.
A Service is used via two basic patterns:
Sending commands to it, via startService().
Binding to it, to call an API exposed by that Service, via bindService().
Binding more accurately depicts what you are trying to do ("so I can call methods of the service"), however binding is tricky to get right, particularly when it comes to configuration changes.
Hence, I would recommend first that you sit back and determine completely and precisely why you are using a Service in the first place. ControlPanel, for example, is a name I would associate with a UI, not UI-less ("background") operations. Then and only then can you determine if the command or the binding pattern is appropriate for your use case.
You can do this with one service class.
public static int myStaticMethod(){
return 1;
}
Simply make the methods you need to access static.
I'm facing a strange problem with my app. I have a LocationService that runs in the background. The way I manage its lifecycle is:
In onResume, every activity uses bindService(intent,serviceConnection, BIND_AUTO_CREATE) like that the service is automatically created when needed.
In onStop, every activity uses unbindService(serviceConnection)
This works because when switching activities, the new Activity onResume is called before the old Activity onStop method
The problem I have is, lets say I start from the home screen and I launch the app with an Activity that has a fragment in it. The order of the function call is as follows
Activity onCreate --> setContentView is called here
Activity onResume --> here bindService is called and should create the Service
Fragment onResume
Service onBind method is called
My question is why is there a something else between my bindServiceand onBind calls?? I have a feeling this has something to do with threading issues.
Well, this isn't a very good answer, but why wouldn't there be something else between your bindService() and onBind() calls? You seem to be assuming that when you call bind the system will immediately create and start your service, and no such guarantee is provided.
You haven't indicated whether yours is an IntentService, or just a regular Service, and this might affect the speed with which your service is launched, but my answer would be the same.
Also, I'm assuming that your ServiceConnection object is called, as expected, sometime after your service's onBind() returns.
I say this not based on having read anything definitive, but because I had a similar experience: I was surprised and annoyed at how long it took before my service was created and my ServiceConnection was called, even though I returned from the service's onBind very quickly. (My fragments needed data from the service to create the initial UI so any delay in the creation of the service meant a delay in displaying the initial UI to the user.)
In the end I settled upon launching my service using an Intent rather then a bind, e.g.
Intent si = new Intent( this, com.company.MyService.class );
si.setAction( MyService.SVC_BIND );
startService( si );
I then sent MyService.SVC_UNBIND in place of calling unbind. When I received the UNBIND intent in my service I cleanup and then call stopSelf(). These are user actions - I just named them for how I'm using them.
I believe this was faster, but looking back upon my comments from that code I don't have any specifics. Note that this meant no ServiceConnection, but I'm making some direct calls from the activities into the service, and using LocalBroadcastManager a fair bit.
Another option to consider (in order that your service be started more quickly, if that is your goal here??) is to launch it in Appliction.onCreate(), rather then waiting for Activity.onResume(). All of these options make it necessary to do some extra work to determine when to stop the service, compared to your current, normal, scheme where that is taken care of for you.
In my case, my issue was using android:process attribute for <service> element within Android Manifest, which is supposed to improve performance, but in reallity, maybe it does once the service is running, but it takes a very long while to reach onCreate() (and so also to reach onBind()). For me it was taking minutes. Now Apps and services run smooth and as expected.
More info:
https://developer.android.com/guide/topics/manifest/service-element
I Need some help here, I have a service which I can start or stop whenever I want and using the onStart() command to pass some extras using putExtras() from my activity
But I need some serious basic instructions on how to interact with the already created service.
Please don't refer me to another webpage which already have some implementations, just give me the needed code to interact from my UI activity to the service:
something like this:
public class myActivity extends Activity {
Object ReceivedObjectFromService;
onCreate()
{
some stuff here
myMethod()
}
public class myMethod()
{
//do some stuff with the ReceivedObjectFromService
//Don't know how to call this method from the service btw
}
please some help, I don't understand the tutorials on how to interact service to activity or viceversa
Interaction with already created service is no different to starting a brand new service. You just simply call startService() so your client code is no different.
Now, the part which is different is the service itself. In your service, onCreate() must start a background thread or a timer to carry on doing a work. onStart() will receive all startService cases and must in fact add the data it receives in the Intent to an internal list or queue and then in the timer's callback start processing from this queue.
Now you can pass any messages or data you want (even closing the service) using startService and passing data in the Intent that your service understands.
Hope this helps.
I have a Service which tracks the location of the user. Currently, the Service boots when the application starts and stops when the application terminates. Unfortunately, if users keep the application in the background, the Service never stops and drains battery.
I would like the Service to stop when my application is not in the foreground. I was hoping the Application class would let me Override onPause and onResume handlers, but it does not have them. Is there another way I can accomplish this?
I haven't tested this yet, but it looks like if you use Context#bindService() (instead of Context#startService()), the service should stop when no more activities are bound to it. (see Service lifecycle).
Then use onPause()/onResume() in each activity to bind/unbind from the service.
Alternatively, you could add a pair of methods on your service which tell it to start/stop listening for location updates and call it from each activity's onResume()/onPause(). The service would still be running, but the location updates wouldn't be draining the battery.
Reading all the above answers I would suggest Simply add a boolean global flag for each activity & put it in your onResume & onPause & also while launching an Activity Something like this
public void onPause()
{
super.onPause();
activity1IsResumed = true;
}
&same for onResume
& similarly when launching a new Activity
startActivityForResult(myintent ,0);
activity2IsResumed = true;
activity1IsResumed = false;
then in your Service simply check
if(activity1IsResumed || activity2IsResumed || activity3IsResumed)
{
//your logic
}
else
{
//another logic
//or dont run location tracker
}
& you are done!
You should override the onPause and onResume methods on your Activity. If you have multiple activities you may want to have a common base class for them and put the start/stop logic into the base class.
I have not tried this approach but I think you can override the home key of android device by using KeyEvent.KEYCODE_HOME and you can use stopService(Intent) to stop your service and when again application resumes, you can write startService(Intent) in the onResume() method of your Activity.
This way I think your service will only stop when user explicitly presses home button to take application in the background and not when he switches from one activity to another.
What I would suggest is overriding the onPause/onReume methods as others have said. Without knowing more about the flow of your application and interactions between Activities, I can't give much more information beyond guesswork.
If your Activities are persistent, however, my recommendation would be to utilize the Intents better when switching between Activities.
For instance, each Activity should have a boolean "transition" flag. So, when you move from one Activity to the next, you set up an Intent extra:
intent.putExtra("transition",true);
Followed in the receiving Activity by: (in onCreate)
intent.getBooleanExtra("transition",false);
This way, for each Activity that launches, you can know whether it has come from another Activity, or if it has been launched from a home screen launcher. Thus, if it gets a true transition, then onPause should NOT stop the service--that means you will be returning to the previous Activity after it returns. If it receives no "transition" extra, or a false transition, then you can safely assume there is no Activity underneath it waiting to take over for the current one.
On the first Activity, you will simply need to stop the service if you are switching to another Activity, which you should be able to figure out programmatically if one Activity is started from another.
It sounds like the real problem is how to only stop the service when you go to an activity that isn't one of your own? One way would be to in your onPause method to stop the activity. Do this for all your activities. Then override your startActivity method. And in here do a conditional test to confirm that you are purposefully navigating to one of your own. If your are set a flag to true.
Now go back to your on pause overridden method. And only stop your service if the flag is not equal to true. Set the flag to false.
All events that navigate away will close your service. Navigating to your own will leave it intact.
Do the overriding in a base class that all your activities extend.
Writeen in my andolroid. Will post ezaple later.
Try using the Bound Services technique to accomplish this.
Bound Services | Android Developers
You can use bound services in a way such that the service will stop when no activities are bound to it. This way, when the app is not in the foreground, the service will not be running. When the user brings the app back to the foreground, the Activity will bind to the service and the service will resume.
Create methods registerActivity() and unRegisterActivity() in your Application object and implement first method in all you acts onResume() and second in acts onPause().
First method add activity to List<Activity> instance in your app object, unRegisterActivity() checks size of list in every call if==0 stopService();.