Call remote service in Android: IPC (Inter Process Communication)
Android Bind Service
Inter Process Communication (IPC)
Android Service Messenger
Handler
Android Service client
onBind
method too. This method returns an object that implements IBinder
, that can be used to interact with the service. There are three way we can create a bound service:
- Extending IBinder interface
- Using Messenger
- Using AIDL
Implementing bound service with Android Messenger
Service based on Messenger can communicate with other components in different processes, known as Inter Process Communication (IPC), without using AIDL. To implement a service like this we need:- A service handler: this component handles incoming requests from clients that interact with the service itself.
- A Messenger: this class is used to create an object implementing
IBinder
interface so that a client can interact with the service.
So let’s implement the Service. As example we can suppose we want to create a service that receives a string and converts it in upper-case and returns the result to the client.
So as first thing, we create a class that implements
Service
:public class ConvertService extends Service {As told before, we need an Handler to implement incoming request from clients so, we can create an inner class like this:
..
}
class ConvertHanlder extends Handler {In handleMessage we start handling the incoming requests. The first thing we have to do it “decode” the type of request we are handling. We can use for this purpose the
@Override
public void handleMessage(Message msg) {
// This is the action
int msgType = msg.what;
switch(msgType) {
case TO_UPPER_CASE: {
try {
// Incoming data
String data = msg.getData().getString("data");
Message resp = Message.obtain(null, TO_UPPER_CASE_RESPONSE);
Bundle bResp = new Bundle();
bResp.putString("respData", data.toUpperCase());
resp.setData(bResp);
msg.replyTo.send(resp);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
default:
super.handleMessage(msg);
}
}
what
attribute of Message class. Depending on its value we perform different operations: in our case we just convert in upper case a string. We pass the string value a Bundle attached to the Message, so that at line 12 we get the value. We have to send a response to the client, so we create another Message (line 13) that holds the response and attach a new Bundle holding the converted string (line 14-15). At line 16 we send the message back to the client (we will see it later).So in this way, we created our request handler but we have to create an IBinder instance so that a client can use our service. To do it, we need a Messenger:
public class ConvertService extends Service {At line 3, a new instance of Messenger class is created passing the Handler we discussed before. At line 6 we override the
...
private Messenger msg = new Messenger(new ConvertHanlder());;
...
@Override
public IBinder onBind(Intent arg0) {
return msg.getBinder();
}
}
onBind
method and return an instance of IBinder interface. Our Service is ready.At the end we define it in Manifest.xml:
<service android:name=".ConvertService" android:process=":convertprc"/>Notice we used
android:process
so that the Service runs in a different process from the client.Android Service client
Now we have to implement a client that binds to the service and send data to it. We can suppose that the client is an Activity that allows the user to insert a string that has to be converted in uppercase. The activity callsbindService
method to bind to the service created before. When we bind to a “remote” service, using bindService method, we need to provide a callback methods so that we get notified when the bind process is completed and we can “use” the service. We have to create a class that implements ServiceConnection to receive this notification:..At line 8, we create an instance of ServiceConnection override its methods. At line 18 we create a Messanger that we use, later, to get the IBinder instance so that we can send the messages to our service. Finally at line 24 we bind to the service specifying the service class and the callback interface
private ServiceConnection sConn;
private Messenger messenger;
..
@Override
protected void onCreate(Bundle savedInstanceState) {
// Service Connection to handle system callbacks
sConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
messenger = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We are conntected to the service
messenger = new Messenger(service);
}
};
...
// We bind to the service
bindService(new Intent(this, ConvertService.class), sConn,
Context.BIND_AUTO_CREATE);
..
}
Now we need a "receiving" handler to manage the service response:
// This class handles the Service responseThis handler behaves like the one in the service implementation, it extracts the response from the Bundle attached to the Message and show the result to the user at line 11.
class ResponseHandler extends Handler {
@Override
public void handleMessage(Message msg) {
int respCode = msg.what;
switch (respCode) {
case ConvertService.TO_UPPER_CASE_RESPONSE: {
result = msg.getData().getString("respData");
txtResult.setText(result);
}
}
}
}
The last thing we have to cover is sending from the Activity to the Service the string that has to be converted. In this case we can suppose we have a Button in our interface that when user clicks it, the Activity sends the data:
btn.setOnClickListener(new View.OnClickListener() {Please notice that at line 9 we set the reply Messenger that will be used the the service when it has to send back the response.
@Override
public void onClick(View v) {
String val = edt.getText().toString();
Message msg = Message
.obtain(null, ConvertService.TO_UPPER_CASE);
msg.replyTo = new Messenger(new ResponseHandler());
// We pass the value
Bundle b = new Bundle();
b.putString("data", val);
msg.setData(b);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
0 comments:
Post a Comment