The RemoteService. java, IRemoteService. aidl, IRemoteServiceCallback. aidl, and ISecondary. aidl files involved in the Remote Service Controller in this and next examples.
Android Interface Definition Language (AIDL) is similar to the IDL of other systems that support remote method calling RMI. It defines the Interface conventions used between the Service and the Client, this remote call is generally implemented through the inter-process communication mechanism (IPC. In the Android system, a Process generally cannot directly access the memory space of other processes. The Android system supports the use of AIDL to call service interfaces between different processes.
Before designing the AIDL interface, you must realize that the AIDL interface is implemented through direct function calls, however, the Thread of this remote call varies with whether the caller and the Service provider belong to the same Process:
If the caller and Service belong to the same Process (or Local Process), the AIDL Call will be executed in the same thread as the caller. Therefore, if your application only uses the Local Process to access AIDL Call, there is no need to use the AIDL interface and use the Binder. For details, refer to the Android ApiDemo sample resolution (39 ): app-> Service-> Local Service Binding.
If you use Remote Process to call AIDL, Android uses the Thread pool managed by the current Process to distribute function calls. Therefore, your Service must be able to process the AIDL Call triggered by multiple processes. In other words, the implementation of the AIDL interface must be Thread-safe.
The oneway keyword can modify the behavior of remote calls. When the oneway keyword is used, the remote call will be returned immediately after the call, which is similar to asynchronous call.
To define the AIDL interface, follow these steps:
The AIDL Interface definition is defined in the. aidl file using the Java Interface syntax, and must be stored in the src directory of the Service and Client at the same time. When Eclipse is used for compilation, the Android SDK automatically generates the corresponding IBinder interface definition (defined in the gen directory) according to the. aidl interface definition. The Service must be defined by this IBinder interface. The Client can then bind a Service to access these methods.
1. Create a. aidl File
The AIDL Interface definition uses the same syntax as the Java Interface definition. Each. aidl file can only define one calling Interface, and can only define Interface methods, but cannot contain static variable definitions. By default, AIDL supports int, long, char, boolean, String, CharSequence, List, and Map variable types. You can also reference other types defined in. aidl.
The following is the definition of IRemoteService. aidl,
[Java]
Package com. example. android. apis. app;
Import com. example. android. apis. app. IRemoteServiceCallback;
/**
* Example of defining an interface for calling on to a remote service
* (Running in another process ).
*/
Interface IRemoteService {
/**
* Often you want to allow a service to call back to its clients.
* This shows how to do so, by registering a callback interface
* The service.
*/
Void registerCallback (IRemoteServiceCallback cb );
/**
* Remove a previusly registered callback interface.
*/
Void unregisterCallback (IRemoteServiceCallback cb); <br/>
}
Package com. example. android. apis. app;
Import com. example. android. apis. app. IRemoteServiceCallback;
/**
* Example of defining an interface for calling on to a remote service
* (Running in another process ).
*/
Interface IRemoteService {
/**
* Often you want to allow a service to call back to its clients.
* This shows how to do so, by registering a callback interface
* The service.
*/
Void registerCallback (IRemoteServiceCallback cb );
/**
* Remove a previusly registered callback interface.
*/
Void unregisterCallback (IRemoteServiceCallback cb); <br/>
}
During compilation, the Android SDK automatically generates the corresponding IRemoteService. java in the gen directory.
2. implement this AIDL Interface
During compilation, the Android SDK automatically generates the corresponding IRemoteService In the gen directory. java, this file defines a subclass of Stub (IRemoteService. stub), Stub defines. aidl-defined abstract method implementation. In addition, Stub defines several Help methods. For example, if the asInterface () parameter is an IBinder object (usually passed in by onServiceConnected () in the Client), a Stub instance is returned for the Client to use.
The implementation of IRemoteService. Stub in RemoteService is as follows:
[Java]
/**
* The IRemoteInterface is defined through IDL
*/
Private final IRemoteService. Stub mBinder = new IRemoteService. Stub (){
Public void registerCallback (IRemoteServiceCallback cb ){
If (cb! = Null) mCallbacks. register (cb );
}
Public void unregisterCallback (IRemoteServiceCallback cb ){
If (cb! = Null) mCallbacks. unregister (cb );
}
};
/**
* The IRemoteInterface is defined through IDL
*/
Private final IRemoteService. Stub mBinder = new IRemoteService. Stub (){
Public void registerCallback (IRemoteServiceCallback cb ){
If (cb! = Null) mCallbacks. register (cb );
}
Public void unregisterCallback (IRemoteServiceCallback cb ){
If (cb! = Null) mCallbacks. unregister (cb );
}
};
3. Expose the interface to Clients
After defining. aidl and implementing the definition of the AIDL interface, you need to provide this interface to the Client. The method is to derive the Service and provide the onBind method to return an instance of Stub implemented above.
[Java]
Public class RemoteService extends Service {
...
@ Override
Public IBinder onBind (Intent intent ){
// Select the interface to return. If your service only implements
// A single interface, you can just return it here without checking
// The Intent.
If (IRemoteService. class. getName (). equals (intent. getAction ())){
Return mBinder;
}
If (ISecondary. class. getName (). equals (intent. getAction ())){
Return mSecondaryBinder;
}
Return null;
}
Public class RemoteService extends Service {
...
@ Override
Public IBinder onBind (Intent intent ){
// Select the interface to return. If your service only implements
// A single interface, you can just return it here without checking
// The Intent.
If (IRemoteService. class. getName (). equals (intent. getAction ())){
Return mBinder;
}
If (ISecondary. class. getName (). equals (intent. getAction ())){
Return mSecondaryBinder;
}
Return null;
}
RemoteService defines two. aidl interfaces for the Client to use IRemoteService. aidl and ISecondary. aidl.
With the AIDL definition, and the Service defines the AIDL implementation that can be used by the Client. Next let's take a look at the implementation steps of the Client:
The. aidl definition contains the src directory. Because the Service in this example contains the Client in ApiDemos,. aidl has been defined in src.
Generate the IBinder interface definition based on the. aidl interface (automatically generated by the Android SDK tool during compilation ).
Implement ServiceConnection Interface
Call Context. bindService to bind the Service to be called.
In the onServiceConnected method of ServiceConnection, use YourInterfaceName. Stub. asInterface (IBinder) Service) to convert the service type to YourInterfaceName Based on the passed IBinder object (called service.
Call the method defined by YourInterfaceName. The DeadObjectException exception must be caught here. DeadObjectException will be thrown when the link is broken.
After using the Service, use Context. unbindService to disconnect the binding with the Service.
In the Remote Service Binding example, the Service implements two services:
IRemoteService: Provides registerCallback and unregisterCallback for registering or canceling a Client Callback in RemoteCallbackList.
ISecondary: the service that the Client calls. getPid returns the Process ID of the current Process. BasicTypes describes common parameter type usage. In this example, the Client is used.
A mHandler is defined in the main thread of RemoteService. It adds the value to 1 every second and sends the new value to the registered Client through IRemoteServiceCallback.
[Java]
Int value = ++ mValue;
// Broadcast to all clients the new value.
Final int N = mCallbacks. beginBroadcast ();
For (int I = 0; I <N; I ++ ){
Try {
MCallbacks. getBroadcastItem (I). valueChanged (value );
} Catch (RemoteException e ){
// The RemoteCallbackList will take care of removing
// The dead object for us.
}
}
MCallbacks. finishBroadcast ();
// Repeat every 1 second.
SendMessageDelayed (obtainMessage (REPORT_MSG), 1*1000 );
Int value = ++ mValue;
// Broadcast to all clients the new value.
Final int N = mCallbacks. beginBroadcast ();
For (int I = 0; I <N; I ++ ){
Try {
MCallbacks. getBroadcastItem (I). valueChanged (value );
} Catch (RemoteException e ){
// The RemoteCallbackList will take care of removing
// The dead object for us.
}
}
MCallbacks. finishBroadcast ();
// Repeat every 1 second.
SendMessageDelayed (obtainMessage (REPORT_MSG), 1*1000 );
When this example is run, if the start Service of Remote Service Controller is not run in advance, the value starts from 1 and Adds 1 to every 1 second.
Let's take a look at how the Client binds the Service.
[Java]
BindService (new Intent (IRemoteService. class. getName ()),
MConnection, Context. BIND_AUTO_CREATE );
BindService (new Intent (ISecondary. class. getName ()),
MSecondaryConnection, Context. BIND_AUTO_CREATE );
BindService (new Intent (IRemoteService. class. getName ()),
MConnection, Context. BIND_AUTO_CREATE );
BindService (new Intent (ISecondary. class. getName ()),
MSecondaryConnection, Context. BIND_AUTO_CREATE );
Note that Context. BIND_AUTO_CREATE indicates that if the Service is Destroy for some reason during the binding process, Android will automatically restart the bound Service. You can click Kill Process to Kill the Service and check the result :-).
In RemoteService. Binding, a mHandler is defined to display the current Value returned from the Service. The IRemoteServiceCallback interface of Servcie to send back to the Client also needs the corresponding AIDL definition. MHandler is used because valueChanged requires updating the UI. Android Handler usage overview.
In this example, the unBind Service is unbound from the Service. If you do not run the start Service of the Remote Service Controller in advance, this operation will cause the Destory Service, because the "Bound" Service is automatically exited when it is not Bound to the Service, the Value will be counted from 1 next time it is Bound.
Author: mapdigit