Implementing a bound service

Bound services are services that allow users to bind themselves to them and ask for information. The examples of bound services can be seen in the location, and sensor services are natively run on modern Android phones. The principal addition of the bound service in comparison to the started service is its ability to accept clients' requests. The clients bind themselves to services using an IBinder instance. In this recipe, we will see how to implement a bound service and its Binder.

Getting ready

To follow this recipe, create a new project in the services solution that we created earlier and name it BoundService.

How to do it...

Let's have a look at steps required to implement a bound service:

  1. Create a new class in the BoundService project and name it MyBoundService. As this class is the service, we have to add the [Service](and subclass Service) attribute and the OnStartCommand()method, as seen in the previous recipe. Additionally, MyBoundService contains a reference to an IBinder object; override the OnBind()method, shown as follows:
    [Service]
    [IntentFilter(new String[]{"ca.services.MyBoundService"})]
    public class MyBoundService : Service {
      IBinder _myBinder = null;
    
      public String SayHello() {
        return "HelloWorld";
      }
    
      public override StartCommandResult OnStartCommand (Android.Content.Intentintent, StartCommandFlagsflags, intstartId) {
        Log.Debug ("MyBoundService", "StartCommandResult");
        this._myBinder = new MyBoundServiceBinder (this);
        return StartCommandResult.NotSticky;
      }
    
      public override IBinder OnBind (Intent intent) {
        Log.Debug ("MyBoundService", "NewClient");
        return _myBinder;
      }
    }
  2. Create a new class named MyBoundServiceBinder that extends the Binder class and owns a reference to MyBoundService. The constructor of MyBoundServiceBinder takes MyBoundService as an argument and populates the private reference with it. Finally, MyBoundServiceBinder has a getter that returns the MyBoundService reference:
    public class MyBoundServiceBinder : Binder {
      private MyBoundService _myBoundService;
    
      public MyBoundService BoundService {
        get{return _myBoundService;}
      }
    
      public MyBoundServiceBinder (MyBoundService_myBoundService) {
        this._myBoundService = _myBoundService;
        Log.Debug ("MyBoundServiceBinder", "NewBinder");
      }
    }
  3. Add a reference to MyBoundServiceBinder in your main activity the same as an IsBound Boolean. Also, add a consumerService() method, shown as follows:
    [Activity(Label="BoundService",MainLauncher=true)]
    public class MainActivity : Activity {
      private MyBoundServiceBinder _myBinder;
      private Boolean _IsBound;
    
      public MyBoundServiceBinder Binder {
        get{ return_myBinder; }
        set{ _myBinder=value; }
      }
    
      public Boolean IsBound {
        get{ return_IsBound; }
        set{ _IsBound=value; }
      }
    
      public void ConsumeService() {
        Log.Debug ("MainActivity",_myBinder.BoundService.SayHello ());
      }
    }
  4. Create a new class named MyBoundServiceConnection that implements the IServiceConnection interface and owns a reference to MyBoundService. The MyBoundServiceConnection class implements the OnServiceConnected() and OnServiceDisconnected() methods belonging to the IServiceConnection interface and contains a reference to the main activity:
    publicclassMyBoundServiceConnection:Java.Lang.Object,IServiceConnection {
      MainActivity _myActivity;
    
      public MyBoundServiceConnection (MainActivity activity) {
        this._myActivity = activity;
      }
    
      public void OnServiceConnected (ComponentName name,IBinder service) {
        Log.Debug ("MyBoundServiceConnection", "IncomingConnection");
        var boundServiceBinder = service asMyBoundServiceBinder;
        if (boundServiceBinder != null) {
          _myActivity.Binder = boundServiceBinder;
          _myActivity.isBinded = true;
          _myActivity.consumeService ();
        }
      }
    
      public void OnServiceDisconnected (ComponentName name) {
        _myActivity.isBinded = false;
      }
    }
  5. Bind your MainActivity to the MyBoundService service using the BindService() method that takes Intent as arguments, an implementation of IServiceConnection, and a Bind flag:
    protected override void OnCreate(Bundle bundle) {
      base.OnCreate (bundle);
    
      Intent myBoundServiceIntent = new Intent("ca.services.MyBoundService");
      StartService (myBoundServiceIntent);
    
      cnx = new MyBoundServiceConnection (this);
      BindService (myBoundServiceIntent, cnx, Bind.AutoCreate);
    
    }
  6. Run your application. The following lines will appear in the console:
    [MyBoundService] StartCommandResult
    [MyBoundServiceBinder] New Binder
    [MyBoundService] New Client
    [MyBoundServiceConnection] Incoming Connection
    [MainActivity] Hello World
    

How it works...

In order to understand how it works, we first need to understand the sequence in which the objects interact with each other. The following figure depicts a simplified UML sequence diagram of the collaborations between the objects:

How it works...

First, in the OnCreate() method, we make a call to the StartService() method in the StartService assembly. This assembly holds code and Xamarin. Android will take care of creating MyBoundService and triggering a call to the OnStartCommand()method. Note that there is no message from MyBoundService to MainActivity to inform MainActivity that MyBoundService has started correctly. Indeed, the StartService() method triggers the start and doesn't wait for an acknowledgment from MyBoundService. Then, MainActivity obtains a new MyBoundServiceConnection and asks the BindingAssembly to bind the MyBoundService service. The BindingAssembly will trigger the OnBind() method of MyBoundService and the OnBindService() method of MyBoundServiceConnection when the binding gets completed. Finally, MyBoundServiceConnection will invoke the ConsumeService() method, and the MainActivity class will consume MyBoundService.SayHello() method.

Note

You may wonder why we don't call MyBoundService.SayHello() method directly after BindService and remove the ConsumeService() method? The response is simple, we don't know how long it will take for the service to bound effectively, and MyBoundServiceBinder may be null if we don't wait long enough. We can have an infinite while(!IsBound){} in order to wait for the Boolean to be true. However, the current solution avoids a potential infinite loop and stays simple by avoiding the use of Thread wait and join.

To summarize, clients use MyBoundServiceBinder to obtain a reference of MyBoundService, and call a public method on the service. MyBoundServiceBinder gets populated after the asynchronous call to the BindingAssembly that triggers the OnBind() and OnBindService() methods. Once the OnBindService() method has been executed, we can be sure that the reference to MyBoundServiceBinder has been populated, and we can start using the service.

There's more...

If you want to be sure that your application is running your services, you can simply access the running application on your phone (or emulator) under Settings | Apps | Running, and check how many services are running. In the following picture, we can see one service and one process for the BoundService application:

There's more...

See also

See also the next section to learn how to send notifications from Android services.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.32.230