Implementing a Remote Interface Android

Sometimes it is useful to have more control over a service than just system calls to start and stop its activities. However, before a client application can bind to a service for making other method calls, you need to define the interface. The Android SDK includes a useful tool and file format for remote interfaces for this purpose.

To define a remote interface, you must declare the interface in an AIDL file, implement the interface, and then return an instance of the interface when the onBind() method is called.

Using the example GPXService service we already built in this chapter, we now create a remote interface for it. This remote interface has a method, which can be called especially for returning the last location logged. You can use only primitive types and objects that implement the Parcelable protocol with remote service calls. This is because these calls cross process boundaries where memory can’t be shared. The AIDL compiler handles the details of crossing these boundaries when the rules are followed. The Location object implements the Parcelable interface so it can be used.

Here is the AIDL file for this interface, IRemoteInterface:

package com.androidbook.services;
interface IRemoteInterface {
Location getLastLocation();
}

When using Eclipse, you can add this AIDL file, IRemoteInterface.aidl, to the project under the appropriate package and the Android SDK plug-in does the rest. Now we must implement the code for the interface. Here is an example implementation of this interface:

private final IRemoteInterface.Stub
mRemoteInterfaceBinder = new IRemoteInterface.Stub() {
public Location getLastLocation() {
Log.v(“interface”, “getLastLocation() called”);
return lastLocation;
}
};

The service code already stored off the last location received as a member variable, so we can simply return that value. With the interface implemented, it needs to be returned from the onBind() method of the service:

@Override
public IBinder onBind(Intent intent) {
// we only have one, so no need to check the intent
return mRemoteInterfaceBinder;
}

If multiple interfaces are implemented, the Intent passed in can be checked within the onBind() method to determine what action is to be taken and which interface should be returned. In this example, though, we have only one interface and don’t expect any other information within the Intent, so we simply return the interface.

We also add the class name of the binder interface to the list of actions supported by the intent filter for the service within the AndroidManifest.xml file. Doing this isn’t required but is a useful convention to follow and allows the class name to be used. The following block is added to the service tag definition:

<action android:name =
“com.androidbook.services.IRemoteInterface” />

The service can now be used through this interface. This is done by implementing a ServiceConnection object and calling the bindService() method. When finished, the unbindService() method must be called so the system knows that the application is done using the service. The connection remains even if the reference to the interface is gone.

Here is an implementation of a ServiceConnection object’s two main methods, onService Connected() and onService Disconnected():

public void onServiceConnected(ComponentName name,
IBinder service) {
mRemoteInterface =
IRemoteInterface.Stub.asInterface(service);
Log.v(“ServiceControl”, “Interface bound.”);
}
public void onServiceDisconnected(ComponentName name) {
mRemoteInterface = null;
Log.v(“ServiceControl”,
“Remote interface no longer bound”);
}

When the onServiceConnected() method is called, an IRemoteInterface instance that can be used to make calls to the interface we previously defined is retrieved. A call to the remote interface looks like any call to an interface now:

Location loc = mRemoteInterface.getLastLocation();

To use this interface from another application, you should place the AIDL file within the project and appropriate package. The call to onBind() triggers a call to the onService Connected() after the call to the service’s onCreate() method. Remember, the onStart() or onStartCommand() methods are not called in this case.

bindService(new Intent(IRemoteInterface.class.getName()),
this, Context.BIND_AUTO_CREATE);

In this case, the Activity we call from also implements the ServiceConnection interface. This code also demonstrates why it is a useful convention to use the class name as an intent filter. Because we have both intent filters and we don’t check the action on the call to the onBind() method, we can also use the other intent filter, but the code here is clearer.

When done with the interface, a call to unbindService() disconnects the interface. However, a callback to the onServiceDisconnected() method does not mean that the service is no longer bound; the binding is still active at that point, just not the connection.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Android Topics