现在的位置: 首页 > 综合 > 正文

Android Java basic knowledge —AIDL3

2013年12月13日 ⁄ 综合 ⁄ 共 5801字 ⁄ 字号 评论关闭

Using the Android Interface Definition Language (AIDL) to make a Remote Procedure Call (RPC) in Android

There are different ways to communicate with a Service. A commonly used approach is to use Intents where the Service can respond according to the intent action. This is easily implemented but if the Service is providing many different operations the resulting code might become complex which will result in a hardly maintainable code. Furthermore, when using Intents the developer always has to take care of adding the parameters to the intent and after the result intent was received the result-parameters have to be retrieved from the intent. This will result in an increased programming overhead within the client each time a remote functionality is called which can lead to error-prone code. To avoid these disadvantages you can use the built-in Remote Procedure Call (RPC) mechanism of Android. To demonstrate the use of RPCs in Android I’ve created a basic example. This example consists of two apps where the first contains a Service and the second an Activity. The Activity will connect to the Service using the Android RPC mechanism and will query a String from that Service. The Service and the Activity contain Log output so that you can follow each step of the communication process during an RPC call (using adb logcat). As always you can browse or download the source code of the example App at our SVN repository at Google Code (http://code.google.com/p/android-aidl-ipc-rpc-example/) or use svn to check the project out and your allowed to reuse portions of this code as you wish.

The basic concept of RPCs in Android

In Android a Service can export multiple remote interfaces. These remote Interfaces offer functionality which can be used from clients (e.g. other activities or services).

 

 

Overview of the Communication between an Activity and a Service using AIDL IPC / RPC

 

 

To describe the methods which can be remotely called Android is using the Android Interface Definition Language (AIDL). The format of the AIDL is quite similar to the java interface syntax and all parameters can be either basic java data types or Parcelables. The compiler will automatically generate an abstract Stub class and an interface out of this description file. Because this post is supposed to be a basic example of RPC in Android I won’t explain how to use Parcelable parameters but I might extend the example with another posting later on.

If a client wants to call methods in a remote service it can just call the bindService –method which is defined within the android.content.Context and is therefore available in Activities and Services. The method is declared as followed:

1 public boolean bindService (Intent service, ServiceConnection conn, intflags)

To bind a remote service we must define these three parameters:

  • Intent service – this parameter is the intent which will be used to locate the service
  • ServiceConnection conn – the service connection manages the connection to the remote interface. The ServiceConnection class contains callbacks for an established connection and an unexpectedly closed connection:
    • public void onServiceConnected (ComponentName name, IBinder service)
    • public void onServiceDisconnected (ComponentName name)

    It is important to understand that the onServiceDisconnected method will only be called if the connection was closed unexpectedly and not if the connection was closed by the client.

  • int flags – this parameter defines options which will be used during the bind process there are four possible parameters which can be combined (XOR):
    • 0 – no options
    • BIND_AUTO_CREATE – this flag will automatically create the service if it is not yet running
    • BIND_DEBUG_UNBIND – this flag will result in additional debug output when errors occur during the unbinding of the service. This flag should only be used during debugging
    • BIND_NOT_FOREGROUND – this flag will limit the service process priority so that the service won’t run at the foreground process priority.

A call to the bindService method will establish a connection to the service asynchronously and the callback within the ServiceConnection will be called once the remote interface was returned by the Service. Within this remote interface all the functionality provided by the service is and it can be used by the client like a local object. This allows the client to easily call multiple methods in the service without the need of always rethinking about the fact that it is a remote service.

The only point where additional attention is required is during the bind procedure because this is done asynchronously by the Android system. So after binding the Service you can’t just directly call remote methods but you have to wait for a callback which notifies your client that the connection was established.

Defining the Remote Interface

The Service in the example has a method which will generate a String containing the current time. To make this method accessible to remote clients we have to declare this functionality within an AIDL file. The first thing we need to declare in this file is the package where the interface is located. In our example this will be com.appsolut.example.aidlMessageService.  This statement is followed by the interface tag which will declare the name of the interface (IRemoteMessageService). Inside the interface block we can define methods. In our example we provide a method which will return a String String getMessage();. The content of this file must be saved in an .aidl file which is named like the interface is called. Furthermore the file must be located within the package folder.

01 /* The package where the aidl file is located */
02 package com.appsolut.example.aidlMessageService;
03  
04 /* The name of the remote service */
05 interface IRemoteMessageService {
06  
07     /* A simple Method which will return a message string */
08     String getMessage();
09  
10 }

The compiler will now automatically generate the interface IRemoteMessageService which contains an abstract class called Stub. The generated file will be placed within the gen folder of your project.

Implementing the Remote Interface

The functionality of the Remote Interface is now described by the interface but we still have to implement this interface. In our example this is done in the TimeMessageService class. Generally the implementations of such a remote interface have to extend the abstract Stub class within the interface. The Stub class contains an abstract method which is called like the method which we declared in the AIDL interface. Within this method we can implement our functionality which will be executed by a remote client. Furthermore, our class contains a field variable containing a reference to the service because we will access a method in the service from our remote interface.

01 public class TimeMessageService extends IRemoteMessageService.Stub {
02  
03     private final AIDLMessageService service;
04  
05  &nb

抱歉!评论已关闭.