Android service - invoking methods and passing objects, without binding - android

I have an app where I need to establish and maintain a bluetooth connection with another phone. However, this connection needs to remain alive even if the screen turns off.
So the way I've done this is 1) make it a service so the connection can exist in the background and 2) make an explicit call to start/stop the service instead of binding it to the activity (I believe if the screen goes off, the activity goes away, thus the service will stop)
This has now made things more complicated because my service has methods that I need to be able to manually invoke. For example, I want to start bluetooth discovery when the user clicks a button. So on button click, I need to tell this service to call my startDiscovery method. There are many situations like this (e.g. open a socket, pair to a device etc) where I need to manually call service methods
A lot of what I've read on this topic solves this by binding the service, but this I cannot do as explained earlier
Without binding, others suggest to use some sort of event bus, where on button click I send a message to the service. When it receives the message, it checks what type of message it is and then invokes the appropriate method.
OK, this works, but what if my method requires me to pass something into it? For example, lets say I have a list or something that I need to send over bluetooth. So I have a method in my Service that takes a list object, serializes it and sends it over BT to the other phone. But this doesn't seem possible with a basic messaging/event bus system
In sum, how do I pass an object through to a method in a service that is not bound to an activity, but instead has been manually started with startService?
I have seen this question here, but that method only seems to allow me to send objects when I start the service. In my case, the service is already started and sits in the background handling bluetooth traffic. I need to be able to invoke methods and pass objects while the service is already running

I have done something similar in my service. Sometimes i need to manually hide the notification that the service created. So i made the method public and static so it can be called anywhere like this:
public static void hideNotification(){
notificationManager.cancel(0);
}
Then call it in your activity like this: MyService.hideNotification()
EDIT
If you do not want a static method, you can create an empty constructor for your service and then when you need to call the method, create a new instance of your service and call it from that. For example:
In the service:
public class MyService extends Service{
public MyService(){}
public void hideNotification(){
notificationManager.cancel(0);
}
}
When you need to call a method:
MyService service = new Myservice();
service.hideNotification();

Related

Android Service multiple instances

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.

Android onCreate or onStartCommand for starting service

Usually when I create an Android service I implement the onCreate method, but in my last project this does not work. I tried implementing onStartCommand, and this seems to work.
The question is: when I have to implement a service which method is required? Which methods I have to implement? onCreate, onStartCommand, or both? And what is the role of each?
onCreate() is called when the Service object is instantiated (ie: when the service is created). You should do things in this method that you need to do only once (ie: initialize some variables, etc.). onCreate() will only ever be called once per instantiated object.
You only need to implement onCreate() if you actually want/need to initialize something only once.
onStartCommand() is called every time a client starts the service using startService(Intent intent). This means that onStartCommand() can get called multiple times. You should do the things in this method that are needed each time a client requests something from your service. This depends a lot on what your service does and how it communicates with the clients (and vice-versa).
If you don't implement onStartCommand() then you won't be able to get any information from the Intent that the client passes to onStartCommand() and your service might not be able to do any useful work.
Service behave same like Activity Whatever you want to associate once with a service will go in onCreate like initialization
and whenever the service is called using startService. onStartCommand will be called. and you can pass any action to perform . like for a music player , You can play ,pause,stop using action
And you do any operation in service by sending an action and receiving it on onStartCommand
onCreate work like a Constructor.
Edit in Short
onCreate() calls only for the first time you start a Service Whereas onStartCommand() calls everytime you call the startService again. It let you set an action like play,stop,pause music.
public void onStartCommand()
{
if(intent.getAction.equals("any.play")
{
//play song
}
else if(intent.getAction.equals("any.stop")
{}
}

how do I get a response/set callback from startService()

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.

Android: How to backup a database when the application gets closed?

I am needing help to determine the right approach. I want to make a backup of an internal database to a location in the external storage every time the whole application gets interrupted or terminated/destroyed. I want to call this method from a central class called Main which extends Application. The reason for that is, that I need to use several activites and I want to call the backup Method only when needed (like described when the whole application gets destroyed or interrupted by another application). I try to avoid calling this backup method in every activity in their onPause() methods.
I thought about starting a service in the onCreate() method of the application, and starting the backup method when the service gets destroyed. But this won't help in the case of an interrupt, as far as I understood the logic behind services. And also the service doesn't seem to start. startService(new Intent(getApplicationContext(), BackupService.class)); Furthermore I don't think it is a good approach to just use the onDestroy() method of a service, this is not what the service class is made for in my opinion.
So summarizing my Question, do you know a better way then using a service, or if not do you know how I should use the service to be able to call a backup only at the point when the whole app (and not only an activity) is interrupted or destroyed.
First of all, if your service "doesn't seem to start", you are probably doing something wrong.
To accomplish your goal make a backup of an internal database to a location in the external storage every time the whole application gets interrupted or terminated/destroyed:
There are three cases in general here.
If you want to do it in the activity layer:
To know when your application is crashed, you need to implement a custom handler to catch the uncaught exceptions.
To know when your activity is "interrupted", the only way is do it in onPause.
To know when your activity is "terminated", the only way is to do it in onDestroy.
This will require you to have a clear navigation and only do it in your "main activity", and all the other activity starts and comes back to it OR use a flag to indicate if the pause was caused by going to another activity.
If you want to do it in the service layer: (Your way of doing it onDestroy won't allow you to detect interrupted case since you will have to start service sticky to keep it running)
You will have to set up a flag on each activity onBind (you will have to bind it and unbind it) to know if it is a crash/interrupt/termination, which will complicate other part of your code.
To avoid running repetitive code, you will have to create a generic base class and extend your other activities from it.
I use this approach to play background music in one of my games, but I guess it works in this scenario as well.
Use a boolean flag to indicate whether or not your app is launching another part of your app.
boolean movingInApp = false;
....
movingInApp = true;
Intent intent...
.....
public void onPause() {
if(!movingInApp) {
//start service
}
}
public void onResume() {
movingInApp = false;
//Stop service
}
By setting the value of movingInApp to true before launching any intent etc, you can prevent your app from starting the service. Remember to set it to false again later in your onResume() method. If the system makes your app go to the background, this will be false, and your service will be started.
Why dont u have all of your activities extend a base activity which in turn extend the android activity class
I the base activity have backupDB method in the onPause
Therefore u dont have to put it in every activity pause method

help with binding a local service

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.

Categories

Resources