How to get Android Local Service instance - android

I'm starting a service in my application using startService.
I do not want to use bindService as I want to handle the service life time myself.
How can I get an instance to the service started if I do not use bindService? I want to be able to get a handler I've created in the service class to post messages from the activity.
Thanks.
/ Henrik

I do not want to use bindService as I
want to handle the service life time
myself.
That does not mean you have to avoid bindService(). Use both startService() and bindService(), if needed.
How can I get an instance to the
service started if I do not use
bindService?
Either use bindService() with startService(), or use a singleton.

Here's another approach:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
private Binder binder;
#Override
public void onCreate() {
super.onCreate();
binder = new Binder();
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public class Binder extends android.os.Binder {
public MyService getService() {
return MyService.this;
}
}
}
onServiceConnected(...) can cast its argument to MyService.Binder and call getService() on it. This avoids the potential memory leak from having a static reference to the service. Of course, you still have to make sure your activity isn't hanging onto a reference.

Related

What does the Binder class do? What is the meaning of binding in Android bound services?

I am totally confused with bound services. My questions are:
What is the meaning of binding?
What does the Binder class do?
What is meant by "returns an IBinder for interacting with the service"?
What is the IBinder object?
How does the onBind() method work?
These are the a questions on bound services. Please explain in detail. I have already read the documentation, but it is still unclear to me.
Bound service:
A bound service is one that allows application components to bind to it by calling bindService() to create a long-standing connection.
Create a bound service when you want to interact with the service from activities and other components in your application or to expose some of your application's functionality to other applications through interprocess communication (IPC).
To create a bound service, implement the onBind() callback method to return an IBinder that defines the interface for communication with the service. Other application components can then call bindService() to retrieve the interface and begin calling methods on the service. The service lives only to serve the application component that is bound to it, so when there are no components bound to the service, the system destroys it. You do not need to stop a bound service in the same way that you must when the service is started through onStartCommand().
IBinder:
To create a bound service, you must define the interface that specifies how a client can communicate with the service. This interface between the service and a client must be an implementation of IBinder and is what your service must return from the onBind() callback method. After the client receives the IBinder, it can begin interacting with the service through that interface.
onBind():
The system invokes this method by calling bindService() when another component wants to bind with the service (such as to perform RPC). In your implementation of this method, you must provide an interface that clients use to communicate with the service by returning an IBinder. You must always implement this method; however, if you don't want to allow binding, you should return null.
this is an example works as completion to the answer above
inside your service class, initialize the IBinder interface with the object created by our inner class (check step 2)
create an inner class extends Binder that has a getter function, to gain access to the service class
in your service class ovveride onBind function, and use it to return the instance we created in step 1
**The code will clear it for you **
public class MyServiceClass extends Service {
//binder given to client
private final IBinder mBinder = new LocalBinder();
//our inner class
public LocalBinder extends Binder {
public MyServiceClass getService() {
return MyServiceClass.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void doSomeWork(int time){ //we will call this function from outside, which is the whole idea of this **Binding**}
}
Next step is binding itself
in your MainClass or whatever where you want to bind your service,
Defines callbacks for service binding, passed to bindService()
private ServiceConnection serviceConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
MyServiceClass.LocalBinder binder =(MyServiceClass.LocalBinder)service;
timerService = binder.getService();
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
//what to do if service diconnect
}
};
the moment of binding
Intent intent = new Intent(this, MyServiceClass.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
to unbind the service
unbindService(serviceConnection);
then you call the public function we created before in the Service class using the help of [timerService = binder.getService();]
timerService.doSomeWork(50);

How to implement a service that runs only when the app is running?

The app has a service which has to detect how many minutes the app is running and based on that, the service will initiate misc actions.
What is the proper way to implement this?
How can I be sure the service is running ONLY when the app is running in front of the user?
Starting the service seems easy - just start it on splash loading. But the harder part is ending it. I cannot just end it when the user press Back button on the last screen. How to handle situation when a user presses Home screen or some other other app (like phone call, or viber popup, or...) takes over the screen?
I tried taking suggestions from the other theme (How to start a android service from one activity and stop service in another activity?), but this does not handle the situation with Home button or other app taking over the screen.
The app has in total around 10 activities. Is it a proper way to bind this service to all 10 activities and when all are off, the service then turn itself off?
Make a BaseActivity for all of your Activities. In the BaseActivity, do the following:
public class MyActivity extends Activity implements ServiceConnection {
//you may add #override, it's optional
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, MyService.class);
bindService(intent, this, 0);
}
//you may add #override, it's optional
protected void onStop() {
super.onStop();
unbindService(this);
}
public void onServiceConnected(ComponentName name, IBinder binder) {};
public void onServiceDisconnected(ComponentName name) {};
/* lots of other stuff ... */
}
Your BaseActivity will need to implement ServiceConnection interface (or you can use an anonymous inner class), but you can leave those methods empty.
In your Service class, you need to implement the onBind(Intent) method and return an IBinder. The easiest way to do that is like so:
public class MyService extends Service {
private final IBinder localBinder = new LocalBinder();
public void onCreate() {
super.onCreate();
// first time the service is bound, it will be created
// you can start up your timed-operations here
}
public IBinder onBind(Intent intent) {
return localBinder;
}
public void onUnbind(Intent intent) {
// called when the last Activity is unbound from this service
// stop your timed operations here
}
public class LocalBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
}
Bound Service is define specifically for this purpose, you can bind Activities to it, and when all the Activities are gone, it will be stopped as well. The link should contain enough detail for you to implement.

AsynTask inside service: dealing with Screen Orientation

I have a trouble with screen orientation when using AsyncTask even it's inside Service.
My service look like:
public class RequestService extends Service {
private MyBinder binder;
public RequestService(){
binder = new MyBinder(RequestService.this);
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public class MyBinder extends Binder{
private final RequestService service;
public MyBinder(RequestService service){
this.service = service;
}
public RequestService getService(){
return this.service;
}
}
public <T> void sendRequest(Request<T> task, INotifyRequest<T> notify){
// Call excute the asynctask and notify result in onPostExcute
new TaskExecutor<T>(task, notify).execute();
}
}
Update: I use my Service like this:
// start the service
final Intent intent = new Intent(context, serviceClass);
context.startService(intent);
// then bound the service:
final Intent intentService = new Intent(context, serviceClass);
// Implement the Service Connection
serviceConnection = new RequestServiceConnection();
context.getApplicationContext().bindService(intentService, serviceConnection,
Context.BIND_AUTO_CREATE);
When orientation changing, the service is unbound then re-bound, the AsyncTask doesn't notify to update UI. I wonder why it could happen even AsyncTask inside the Service?
I have read this post, but I don't want to lock the screen orientation or something like that. I prefer the Service than IntentService as Service 's flexible, I can use it with the Binder to get Service instance.
So, the question is, is there any way to do thread safe inside the Service rather than AsyncTask?
If you use a bound service keep in mind, that the Service will be destroyed if no Activity is bound. I don't know if you unbind in onPause(), but this would destroy your Service at an orientation change.
Because of this you will loose the Service and the reference to the AsyncTask. Furthermore there is no onRetainInstanceState() available for a Service, to save the AsyncTask and grab it again.
Think about an IntentService in this case it would be the proper way. Or if you wanna keep the Service use startService(), to keep it alive while no Activity is bound. Then you can still bind and unbind from the service the way you want.
The next point is to keep a reference of the AsyncTask. Because you have to set your callback again if the Activity was destroyed. Because the callback reference will still be set to the old Activity.
Hope this helps.
Edit:
Well if you read that maybe you consider using a IntentService or something..
Keep a instance of the AsyncTask in the Service and define a setter in your Task for your callback.
If your Activity binds to the service after the orientation change check, whether the AsyncTask is running. If it's running update the callback. You can use your Binder for that.

Best Practice - Binding Service to an Activity

I have a network Service which runs in the background. I have this global variable mConnection inside the Activity
protected ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
serviceobject = ((NetworkService.MyBinder) binder).getService();
}
public void onServiceDisconnected(ComponentName className) {
serviceobject = null;
}
};
and then I bind the Service in the Activity's onCreate(..) using
bindService(new Intent(this, NetworkService.class),
mConnection,Context.BIND_AUTO_CREATE);
The NetworkService class has an inner class MyBinder
public class MyBinder extends Binder {
NetworkService getService() {
return NetworkService.this;
}
}
Now to invoke any Service method from the Activity, i use the serviceobject and I create an AsyncTask for each method invocation.(I know that invoking Service methods from the Activity nullifies the use of having Services.I use this for light methods which doesn't involve much computation)
This helps me to directly deal with the data from the Service using the serviceobject .
I unbind the Service in the Activity's onDestroy()
#Override
protected void onDestroy()
{
unbindService(mConnection);
super.onDestroy();
}
Is this the best way of doing it or am I wrong somewhere?
I think what you wanna do is to run a Remote Service. That's what ServiceConnection and bindService is used to. The idea is that your service runs in the baackground and any activity can "bind" to it and interact through in interface you define in AIDL.
The access to the service is fast so you can call method from your service from the UI thread without the use ofAsyncTask. That's one benefit.
However the implementation is a bit tedious because you must write this AIDL interface.
I recommend you to read Google's tutorial here: http://developer.android.com/guide/developing/tools/aidl.html
And then to google "Remote Service AIDL" with "tutorial" or "example".
Good Luck.

Accessing a method of a bound service from an IntentReceiver on Android

I'm having a service class that I bind from my main activity with a ServiceConnection to call a method within the service as soon as it is bound. I need to explicitly call the method to pass over the context of my main activity.
If I call this service class from within an IntentReceiver, I need to use peekService to bind to the service. But how can I spawn it's method then? :-s
Best regards / Thanks alot!
S.
peekService returns you IBinder implementation. you need only to call getService() from it and you will get your service object.
Put your code inside your service:
public class LocalBinder extends Binder {
public NotificationService getService() {
return NotificationService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return new LocalBinder();
}

Categories

Resources