Calling the Service from a Client Application

When a client talks to a service, there must be a protocol or contract between the two. With Android, the contract is AIDL. So the first step in consuming a service is to take the service's AIDL file and copy it to your client project. When you copy the AIDL file to the client project, the AIDL compiler creates the same interface-definition file that was created when the service was implemented (in the service-implementation project). This exposes to the client all of the methods, parameters, and return types on the service. Let's create a new project and copy the AIDL file.

1. Create a new Android project named ServiceClient.

2. Create a new Java package named com.syh.

3. Copy the IStockOuoteService.aidl file to the package. Note that after you copy the file to the project, the AIDL compiler will generate the associated Java file.

The service interface that you regenerate serves as the contract between the client and the service. The next step is to get a reference to the service so we can call the getOuote() method. With remote services, we have to call the bindService() method rather than the startService() method. Listing 8-14 shows an activity class that acts as a client of the IStockOuoteService service. The listing also contains the layout file for the activity.

To follow along, create a layout file called main.xml and copy the contents of the main. xml section from Listing 8-14. Then create a new Java package named com.sayed and create an activity called MainActivity within the package. Finally, copy the contents of the MainActivity section from Listing 8-14 to your activity. Realize that the package name of the activity is not that important—you can put the activity in any package you'd like. However, the AIDL artifacts that you create are package-sensitive because the AIDL compiler generates code from the contents of the AIDL file.

Listing 8-14. A Client of the IStockQuoteService Service package com.sayed;

import com.syh.IStockOuoteService;

import android.app.Activity;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.IBinder;

import android.os.RemoteException;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.Toast;

public class MainActivity extends Activity {

private IStockOuoteService stockService = null; /** Called when the activity is first created. */ ^Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedlnstanceState); setContentView(R.layout.main);

Button bindBtn = (Button)findViewByld(R.id.bindBtn); bindBtn.setOnClickListener(new OnClickListener(){

^Override public void onClick(View view) {

bindService(new Intent(IStockOuoteService.class .getName()), serConn, Context.BIND_AUTO_CREATE);

Button unbindBtn = (Button)findViewByld(R.id.unbindBtn); unbindBtn.setOnClickListener(new OnClickListener(){

^Override public void onClick(View view) { unbindService(serConn);

private ServiceConnection serConn = new ServiceConnection() { ^Override public void onServiceConnected(ComponentName name, IBinder service) {

stockService = IStockOuoteService.Stub.aslnterface(service); double val; try {

val = stockService.getOuote("syh");

Toast.makeText(MainActivity.this, "Value from service is "+val+"", Toast.LENGTH_SHORT).show();

} catch (RemoteException ee) {

Log.e("MainActivity", ee.getMessage(), ee);

^Override public void onServiceDisconnected(ComponentName name) { }

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent"

android:layout_height="fill_parent" >

<Button android:id="@+id/bindBtn"

android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bind" />

<Button android:id="@+id/unbindBtn"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="UnBind"

</LinearLayout>

The activity wires up the onClick listener for two buttons: Bind and UnBind. When the user clicks the Bind button, the activity calls the bindService() method. Similarly, when the user clicks UnBind, the activity calls the unbindService() method. Notice that three parameters are passed to the bindService() method: the name of the AIDL service, a ServiceConnection instance, and a flag to autocreate the service.

With an AIDL service, you need to provide an implementation of the ServiceConnection interface. This interface defines two methods: one called by the system when a connection to the service has been established, and one called when the connection to the service has been destroyed. In our activity implementation, we define a private anonymous member that implements the ServiceConnection for the IStockOuoteService. When we call the bindService() method, we pass in the reference to this member. When the connection to the service is established, we obtain a reference to the IStockOuoteService using the Stub and then call the getOuote() method.

Note that the bindService() call is an asynchronous call. It is asynchronous because the process or service might not be running and thus might have to be created or started. Because bindService() is asynchronous, the platform provides the ServiceConnection callback so we know when the service has been started and when the service is no longer available.

Now you know how to create and consume an AIDL interface. Before we move on and complicate matters further, let's review what it takes to build a simple local service vs. an AIDL service. A local service is a service that does not support onBind()—it returns null from onBind(). This type of service is accessible only to the components of the application that is hosting the service. You call local services by calling startService().

On the other hand, an AIDL service is a service that can be consumed both by components within the same process and by those that exist in other applications. This type of service defines a contract between itself and its clients in an AIDL file. The service implements the AIDL contract, and clients bind to the AIDL definition. The service implements the contract by returning an implementation of the AIDL interface from the onBind() method. Clients bind to an AIDL service by calling bindService() and they disconnect from the service by calling unbindService().

In our service examples thus far, we have strictly dealt with passing simple Java primitive types. Android services actually support passing complex types, too. This is very useful, especially for AIDL services, because you might have an open-ended number of parameters that you want to pass to a service and it's unreasonable to pass them all as simple primitives. It makes more sense to package them as complex types and then pass them to the service. Let's see how we can pass complex types to services.

0 0

Post a comment