The previously mentioned Service is a Local Service, that is, the Service and Client are in the same process (that is, within the same application), and the Service lifecycle is subject to the process lifecycle. In practical applications, sometimes you want to use the Service as a background Service, not only by the activity in the same process, but also by other processes. In this case, you need to use bindService, that is, the Remote Service method.
In Android, different apps belong to different processes. A process is the border of a security policy. A process cannot access the storage of other processes (for example, ContentProvider ). In the Remote Service, interprocess commnication (interprocess) involves inter-process communication. A connection must be established between process A and process B for mutual communication or data transmission.
Android provides the Android Interface Definition Language (AIDL) tool to help establish interfaces between IPC, greatly simplifying the developer view. Right is only used to help understand the code. Follow these steps to implement communication between the client and the service:
[1] define the AIDL interface. Eclipse will automatically create the interface IService for the Service
[2] The Client connects to the Service, connects to the Stub exposed to the Client by IService, and obtains the stub object. In other words, the Service provides services to the client through the Stub in the interface, and abstracts IService in IService. stub implementation.
[3] after the Client and Service are connected, the Client can simply call the methods in IService. Stub just like using the local method.
The following example shows how the client obtains the Service from the Remote Service that provides the timed count, called TestRemoteService.
Step 1: Define the interface provided by the service to the client through the aidl File, The ITestRemoteService. aidl file is as follows:
Package com. wei. android. learning. part5;
InterfaceItestremoteservice{
Int getcounter ();
}
We add an I <serviceclassname>. aidl file under the src directory. The syntax is the same as that of Java. In this example, the service is simple and only provides the counter value. Therefore, we define int getcounter () in the interface ().
The aidl file is very simple. eclipse will automatically generate a related Java interface file based on the file, but it is not displayed. If you use the command line tool directly, it will help generate a Java file.
Step 2: Compile the remote service and pass the stub object when connecting to the client through onbind.The testremoteservice. Java file is as follows:
/* The Service provides a timer counter, which is implemented in runnable mode. Let's review the android learning notes (Sany): Example 3 in thread: Message and runnable. In order to avoid interference with attention, this part of the code is grayed out. In addition, showinfo () is provided to track the running status of the service. */
Public class testremoteservice extends Service {
Private handler servicehandler = NULL;
Private int counter = 0;
Private testcountertask mytask = new testcountertask ();
Public voidOncreate(){
Super. onCreate ();
ShowInfo ("remote service onCreate ()");
}
Public voidOndestroy(){
Super. onDestroy ();
ServiceHandler. removeCallbacks (myTask); // stop the counter
ServiceHandler = null;
ShowInfo ("remote service onDestroy ()");
}
Public void onStart (Intent intent, int startId ){
// Enable the counter
Super. onStart (intent, startId );
Servicehandler = new handler ();
Servicehandler. postdelayed (mytask, 1000 );
Showinfo ("remote service onstart ()");
}
// Step 2.1: provide a stub inner class to implement the stub exposed to the client in the specific implementation interface.
PrivateItestremoteservice. Stub stub = new itestremoteservice. Stub (){
// Step 2.1: specify the methods used to implement the interface definition in the aidl file.
Public int getcounter () throws RemoteException {
Showinfo ("getcounter ()");
Return counter;
}
};
// Step 2.2: when the client is connected, onbind () is triggered. The service returns a stub object to the client, so that the client can access the service through the stub object. In this example, Stub is used. getcounter () is used to obtain the current count of the timer. In this example, we pass the same stub object to all clients.
Public ibinder onbind (intent arg0 ){
Showinfo ("onbind ()" + stub );//We specifically tracked the address of the stub object., You can see in the Client Connection Service passed to the client through serviceconnection
Return stub;
}
/* Use the timer counter with runnable, and Add 1 to the counter every 10 seconds. */
Private class testcountertask implements runnable {
Public void run (){
++ Counter;
Servicehandler. postdelayed (mytask, 10000 );
Showinfo ("running" + counter );
}
}
/* ShowInfo () helps us track information to better understand the Service running status */
Private voidShowinfo(String s ){
System. out. println ("[" + getClass (). getSimpleName () + "@" + Thread. currentThread (). getName () + "]" + s );
}
}
Step 3: establish a connection between the client and the service to obtain stub, ServiceTest4.java code:
Public class ServiceTest4 extends Activity {
PrivateItestremoteserviceRemoteService = null;
// Step 3.1 define interface Variables
Private boolean isStarted = false;
PrivateCounterserviceconnectionConn = null;
// Step 3.1 define the connection variable to implement the serviceconnection Interface
Protected void onCreate (Bundle savedInstanceState ){
... ... // Five buttons trigger startService (), stopService (), bindService (), releaseService (), and invokeService (), respectively. The following two rows, one row shows the Count value obtained from the Service, and one row shows the status.
}
Private void startService (){
Intent I = new Intent ();
I. setClassName ("Com. Wei. Android. Learning","Com. Wei. Android. Learning. part5.testremoteservice"); // There are layers in my package, such as *. part1, *. part2, etc.
Startservice (I); // like the previous local service, enable the service through intent and trigger oncreate () [if service is not enabled]-> onstart ()
IsStarted = true;
UpdateServiceStatus ();
}
Private void stopService (){
Intent I = new Intent ();
I. setclassname ("com. Wei. Android. Learning", "com. Wei. Android. Learning. part5.testremoteservice ");
Stopservice (I); // ondestroy () that triggers the service [if service exists]
Isstarted = false;
Updateservicestatus ();
}
// Step 3.3: bindservice () establishes a connection between services through a class that implements the serviceconnection interface, and notices the parameter context. bind_auto_create, trigger oncreate () [if service does not exist]-> onbind ().
Private void bindservice (){
If (conn = NULL ){
Conn = new counterserviceconnection ();
Intent I = new intent ();
I. setclassname ("com. Wei. Android. Learning", "com. Wei. Android. Learning. part5.testremoteservice ");
Bindservice (I, Conn,Context. BIND_AUTO_CREATE);
UpdateServiceStatus ();
}
}
Private void releaseService (){
If (conn! = Null ){
Unbindservice(Conn );// Disconnect and unbind
Conn = null;
UpdateServiceStatus ();
}
}
Private void invokeService (){
If (Conn! = NULL ){
Try {
Integer counter =Remoteservice. getcounter ();
// Once the client is successfully bound to the Service, you can directly use the method in stub.
Textview t = (textview) findviewbyid (R. Id. st4_notapplicable );
T. settext ("counter value:" + integer. tostring (Counter ));
} Catch (RemoteException e ){
Log. E (getclass (). getsimplename (), E. tostring ());
}
}
}
// Step 3.2 class CounterServiceConnection implements the ServiceConnection interface. Two triggers onServiceConnected () and onServiceDisconnected () must be implemented ()
PrivateClass CounterServiceConnection implements ServiceConnection{
@ Override
Public voidOnServiceConnected(Componentname name, ibinder Service ){
// Obtain the stub object from the connection. Based on our tracking, remoteService is the stub object in the service.
RemoteService = ITestRemoteService. Stub. asInterface (service );
Showinfo ("onserviceconnected ()" + remoteservice );
}
@ Override
Public voidOnServiceDisconnected(Componentname name ){
Remoteservice = NULL;
UpdateServiceStatus ();
ShowInfo ("onServiceDisconnected ");
}
}
Private void updateServiceStatus (){
TextView t = (TextView) findViewById (R. id. st4_serviceStatus );
T. setText ("Service status:" + (conn = null? "Unbound": "bound") + "," + (isStarted? "Started": "not started ";));
}
Private void showInfo (String s ){
System. Out. println ("[" + getclass (). getsimplename () + "@" + thread. currentthread (). getname () + "]" + S );
}
}
Related links:
My android development articles