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();
}
Related
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);
In the Service class:
class AeroBluetoothService extends Service { ...
private final IBinder asBleBinder = new LocalBinder();
public class LocalBinder extends Binder {
AeroBluetoothService getService() {
return AeroBluetoothService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return asBleBinder;
}
In the client Activity:
Intent bindAsBleIntent;
#Override
public void onServiceConnected( ComponentName className, IBinder service ) {
AeroBluetoothService.LocalBinder asBleBinder = (AeroBluetoothService.LocalBinder) service;
asBleServiceRef = asBleBinder.getService();
}
In Client's onCreate():
bindAsBleIntent = new Intent( getApplicationContext(), AeroBluetoothService.class );
bindService( bindAsBleIntent, /*ServiceConnection*/ this, Context.BIND_AUTO_CREATE );
The problem is that when I try to call a Service method from the Client:
asBleServiceRef.scanForAero();
the reference to the Service instance, asBleServiceRef, is null. It is as though the onServiceConnected() callback is not being called (or is passing a null argument).
I copied this code quite carefully from an Android example. I just noticed that the example calls bindService() from its onStart() method, whereas I'm calling from onCreate(). Could that make any difference? What's the problem?
As #avinash correctly saw, the problem was simply neglecting to declare the Service in the Manifest.
I'm developing android wear project with Service extends WearableListenerService.
When I'm trying to add Service binder I see this error
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
DataLayerListenerService getService() {
return DataLayerListenerService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
Error:(196, 20) error: onBind(Intent) in DataLayerListenerService cannot override onBind(Intent) in WearableListenerService
overridden method is final
Is it possible to bind WearableListenerService somehow? How to pass data from WearableListenerService to Activity without using broadcasts?
You not have to use Bind.
You can communicate through mGoogleApiClient.
Sending data from an Activity to WearableListenerService
This Answer help your problem solve.
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.
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.