AIDL (Android Interface Definition Language) is similar to other IDLs you might have worked with. It allows you to define the programming interface that both the client and service agree upon in order to communicate with each other using interprocess communication (IPC). On Android, one process cannot normally access the memory of another process. So to talk, they need to decompose their objects into primitives that the operating system can understand, and marshall the objects across that boundary for you. The code to do that marshalling is tedious to write, so Android handles it for you with AIDL.

Note:Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface byimplementing a Binderor, if you want to perform IPC, but donotneed to handle multithreading, implement your interfaceusing a Messenger. Regardless, be sure that you understandBound Servicesbefore implementing an AIDL.

Before you begin designing your AIDL interface, be aware that calls to an AIDL interface are direct function calls. You should not make assumptions about the thread in which the call occurs. What happens is different depending on whether the call is from a thread in the local process or a remote process. Specifically:

  • Calls made from the local process are executed in the same thread that is making the call. If this is your main UI thread, that thread continues to execute in the AIDL interface. If it is another thread, that is the one that executes your code in the service. Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn't be using AIDL at all, but should instead create the interface byimplementing a Binder).
  • Calls from a remote process are dispatched from a thread pool the platform maintains inside of your own process. You must be prepared for incoming calls from unknown threads, with multiple calls happening at the same time. In other words, an implementation of an AIDL interface must be completely thread-safe.
  • Theonewaykeyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from theBinderthread pool as a normal remote call. Ifonewayis used with a local call, there is no impact and the call is still synchronous.

Defining an AIDL Interface

You must define your AIDL interface in an.aidlfile using the Java programming language syntax, then save it in the source code (in thesrc/directory) of both the application hosting the service and any other application that binds to the service.

When you build each application that contains the.aidlfile, the Android SDK tools generate anIBinderinterface based on the.aidlfile and save it in the project'sgen/directory. The service must implement theIBinderinterface as appropriate. The client applications can then bind to the service and call methods from theIBinderto perform IPC.

To create a bounded service using AIDL, follow these steps:

  1. Create the .aidl file

    This file defines the programming interface with method signatures.

  2. Implement the interface

    The Android SDK tools generate an interface in the Java programming language, based on your.aidlfile. This interface has an inner abstract class namedStubthat extendsBinderand implements methods from your AIDL interface. You must extend theStubclass and implement the methods.

  3. Expose the interface to clients

    Implement aServiceand overrideonBind()to return your implementation of theStubclass.

Caution:Any changes that you make to your AIDL interface after your first release must remain backward compatible in order to avoid breaking other applications that use your service. That is, because your.aidlfile must be copied to other applications in order for them to access your service's interface, you must maintain support for the original interface.

1. Create the .aidl file

AIDL uses a simple syntax that lets you declare an interface with one or more methods that can take parameters and return values. The parameters and return values can be of any type, even other AIDL-generated interfaces.

You must construct the.aidlfile using the Java programming language. Each.aidlfile must define a single interface and requires only the interface declaration and method signatures.

By default, AIDL supports the following data types:

  • All primitive types in the Java programming language (such asint,long,char,boolean, and so on)
  • String
  • CharSequence
  • List

    All elements in theListmust be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared. AListmay optionally be used as a "generic" class (for example,List<String>). The actual concrete class that the other side receives is always anArrayList, although the method is generated to use theListinterface.

  • Map

    All elements in theMapmust be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared. Generic maps, (such as those of the formMap<String,Integer>are not supported. The actual concrete class that the other side receives is always aHashMap, although the method is generated to use theMapinterface.

You must include animportstatement for each additional type not listed above, even if they are defined in the same package as your interface.

When defining your service interface, be aware that:

  • Methods can take zero or more parameters, and return a value or void.
  • All non-primitive parameters require a directional tag indicating which way the data goes. Eitherin,out, orinout(see the example below).

    Primitives areinby default, and cannot be otherwise.

    Caution:You should limit the direction to what is truly needed, because marshalling parameters is expensive.

  • All code comments included in the.aidlfile are included in the generatedIBinderinterface (except for comments before the import and package statements).
  • Only methods are supported; you cannot expose static fields in AIDL.

Here is an example.aidlfile:

// IRemoteService.aidlpackage com.example.android;// Declare any non-default types here with import statements/** Example service interface */interface IRemoteService {  /** Request the process ID of this service, to do evil things with it. */  int getPid();  /** Demonstrates some basic types that you can use as parameters  * and return values in AIDL.  */  void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,      double aDouble, String aString);}

Simply save your.aidlfile in your project'ssrc/directory and when you build your application, the SDK tools generate theIBinderinterface file in your project'sgen/directory. The generated file name matches the.aidlfile name, but with a.javaextension (for example,IRemoteService.aidlresults inIRemoteService.java).

If you use Android Studio, the incremental build generates the binder class almost immediately. If you do not use Android Studio, then the Gradle tool generates the binder class next time you build your application—you should build your project withgradle assembleDebug(orgradle assembleRelease) as soon as you're finished writing the.aidlfile, so that your code can link against the generated class.

2. Implement the interface

When you build your application, the Android SDK tools generate a.javainterface file named after your.aidlfile. The generated interface includes a subclass namedStubthat is an abstract implementation of its parent interface (for example,YourInterface.Stub) and declares all the methods from the.aidlfile.

Note:Stubalso defines a few helper methods, most notablyasInterface(), which takes anIBinder(usually the one passed to a client'sonServiceConnected()callback method) and returns an instance of the stub interface. See the sectionCalling an IPC Methodfor more details on how to make this cast.

To implement the interface generated from the.aidl, extend the generatedBinderinterface (for example,YourInterface.Stub) and implement the methods inherited from the.aidlfile.

Here is an example implementation of an interface calledIRemoteService(defined by theIRemoteService.aidlexample, above) using an anonymous instance:

private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {  public int getPid(){    return Process.myPid();  }  public void basicTypes(int anInt, long aLong, boolean aBoolean,    float aFloat, double aDouble, String aString) {    // Does nothing  }};

Now themBinderis an instance of theStubclass (aBinder), which defines the RPC interface for the service. In the next step, this instance is exposed to clients so they can interact with the service.

There are a few rules you should be aware of when implementing your AIDL interface:

  • Incoming calls are not guaranteed to be executed on the main thread, so you need to think about multithreading from the start and properly build your service to be thread-safe.
  • By default, RPC calls are synchronous. If you know that the service takes more than a few milliseconds to complete a request, you should not call it from the activity's main thread, because it might hang the application (Android might display an "Application is Not Responding" dialog)—you should usually call them from a separate thread in the client.
  • No exceptions that you throw are sent back to the caller.

3. Expose the interface to clients

Once you've implemented the interface for your service, you need to expose it to clients so they can bind to it. To expose the interface for your service, extendServiceand implementonBind()to return an instance of your class that implements the generatedStub(as discussed in the previous section). Here's an example service that exposes theIRemoteServiceexample interface to clients.

public class RemoteService extends Service {  @Override  public void onCreate() {    super.onCreate();  }  @Override  public IBinder onBind(Intent intent) {    // Return the interface    return mBinder;  }  private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {    public int getPid(){      return Process.myPid();    }    public void basicTypes(int anInt, long aLong, boolean aBoolean,      float aFloat, double aDouble, String aString) {      // Does nothing    }  };}

Now, when a client (such as an activity) callsbindService()to connect to this service, the client'sonServiceConnected()callback receives themBinderinstance returned by the service'sonBind()method.

The client must also have access to the interface class, so if the client and service are in separate applications, then the client's application must have a copy of the.aidlfile in itssrc/directory (which generates theandroid.os.Binderinterface—providing the client access to the AIDL methods).

When the client receives theIBinderin theonServiceConnected()callback, it must callYourServiceInterface.Stub.asInterface(service)to cast the returned parameter toYourServiceInterfacetype. For example:

IRemoteService mIRemoteService;private ServiceConnection mConnection = new ServiceConnection() {  // Called when the connection with the service is established  public void onServiceConnected(ComponentName className, IBinder service) {    // Following the example above for an AIDL interface,    // this gets an instance of the IRemoteInterface, which we can use to call on the service    mIRemoteService = IRemoteService.Stub.asInterface(service);  }  // Called when the connection with the service disconnects unexpectedly  public void onServiceDisconnected(ComponentName className) {    Log.e(TAG, "Service has unexpectedly disconnected");    mIRemoteService = null;  }};

For more sample code, see theRemoteService.javaclass inApiDemos.

Passing Objects over IPC

If you have a class that you would like to send from one process to another through an IPC interface, you can do that. However, you must ensure that the code for your class is available to the other side of the IPC channel and your class must support theParcelableinterface. Supporting theParcelableinterface is important because it allows the Android system to decompose objects into primitives that can be marshalled across processes.

To create a class that supports theParcelableprotocol, you must do the following:

  1. Make your class implement theParcelableinterface.
  2. ImplementwriteToParcel, which takes the current state of the object and writes it to aParcel.
  3. Add a static field calledCREATORto your class which is an object implementing theParcelable.Creatorinterface.
  4. Finally, create an.aidlfile that declares your parcelable class (as shown for theRect.aidlfile, below).

    If you are using a custom build process, donotadd the.aidlfile to your build. Similar to a header file in the C language, this.aidlfile isn't compiled.

AIDL uses these methods and fields in the code it generates to marshall and unmarshall your objects.

For example, here is aRect.aidlfile to create aRectclass that's parcelable:

package android.graphics;// Declare Rect so AIDL can find it and knows that it implements// the parcelable protocol.parcelable Rect;

And here is an example of how theRectclass implements theParcelableprotocol.

import android.os.Parcel;import android.os.Parcelable;public final class Rect implements Parcelable {  public int left;  public int top;  public int right;  public int bottom;  public static final Parcelable.Creator<Rect> CREATOR = newParcelable.Creator<Rect>() {    public Rect createFromParcel(Parcel in) {      return new Rect(in);    }    public Rect[] newArray(int size) {      return new Rect[size];    }  };  public Rect() {  }  private Rect(Parcel in) {    readFromParcel(in);  }  public void writeToParcel(Parcel out) {    out.writeInt(left);    out.writeInt(top);    out.writeInt(right);    out.writeInt(bottom);  }  public void readFromParcel(Parcel in) {    left = in.readInt();    top = in.readInt();    right = in.readInt();    bottom = in.readInt();  }}

The marshalling in theRectclass is pretty simple. Take a look at the other methods onParcelto see the other kinds of values you can write to a Parcel.

Warning:Don't forget the security implications of receiving data from other processes. In this case, theRectreads four numbers from theParcel, but it is up to you to ensure that these are within the acceptable range of values for whatever the caller is trying to do. SeeSecurity and Permissionsfor more information about how to keep your application secure from malware.

Calling an IPC Method

Here are the steps a calling class must take to call a remote interface defined with AIDL:

  1. Include the.aidlfile in the projectsrc/directory.
  2. Declare an instance of theIBinderinterface (generated based on the AIDL).
  3. ImplementServiceConnection.
  4. CallContext.bindService(), passing in yourServiceConnectionimplementation.
  5. In your implementation ofonServiceConnected(), you will receive anIBinderinstance (calledservice). CallYourInterfaceName.Stub.asInterface((IBinder)service)to cast the returned parameter toYourInterfacetype.
  6. Call the methods that you defined on your interface. You should always trapDeadObjectExceptionexceptions, which are thrown when the connection has broken; this will be the only exception thrown by remote methods.
  7. To disconnect, callContext.unbindService()with the instance of your interface.

A few comments on calling an IPC service:

  • Objects are reference counted across processes.
  • You can send anonymous objects as method arguments.

For more information about binding to a service, read theBound Servicesdocument.

Here is some sample code demonstrating calling an AIDL-created service, taken from the Remote Service sample in the ApiDemos project.

public static class Binding extends Activity {  /** The primary interface we will be calling on the service. */  IRemoteService mService = null;  /** Another interface we use on the service. */  ISecondary mSecondaryService = null;  Button mKillButton;  TextView mCallbackText;  private boolean mIsBound;  /**  * Standard initialization of this activity. Set up the UI, then wait  * for the user to poke it before doing anything.  */  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.remote_service_binding);    // Watch for button clicks.    Button button = (Button)findViewById(R.id.bind);    button.setOnClickListener(mBindListener);    button = (Button)findViewById(R.id.unbind);    button.setOnClickListener(mUnbindListener);    mKillButton = (Button)findViewById(R.id.kill);    mKillButton.setOnClickListener(mKillListener);    mKillButton.setEnabled(false);    mCallbackText = (TextView)findViewById(R.id.callback);    mCallbackText.setText("Not attached.");  }  /**  * Class for interacting with the main interface of the service.  */  private ServiceConnection mConnection = new ServiceConnection() {    public void onServiceConnected(ComponentName className,        IBinder service) {      // This is called when the connection with the service has been      // established, giving us the service object we can use to      // interact with the service. We are communicating with our      // service through an IDL interface, so get a client-side      // representation of that from the raw service object.      mService = IRemoteService.Stub.asInterface(service);      mKillButton.setEnabled(true);      mCallbackText.setText("Attached.");      // We want to monitor the service for as long as we are      // connected to it.      try {        mService.registerCallback(mCallback);      } catch (RemoteException e) {        // In this case the service has crashed before we could even        // do anything with it; we can count on soon being        // disconnected (and then reconnected if it can be restarted)        // so there is no need to do anything here.      }      // As part of the sample, tell the user what happened.      Toast.makeText(Binding.this, R.string.remote_service_connected,          Toast.LENGTH_SHORT).show();    }    public void onServiceDisconnected(ComponentName className) {      // This is called when the connection with the service has been      // unexpectedly disconnected -- that is, its process crashed.      mService = null;      mKillButton.setEnabled(false);      mCallbackText.setText("Disconnected.");      // As part of the sample, tell the user what happened.      Toast.makeText(Binding.this, R.string.remote_service_disconnected,          Toast.LENGTH_SHORT).show();    }  };  /**  * Class for interacting with the secondary interface of the service.  */  private ServiceConnection mSecondaryConnection = new ServiceConnection() {    public void onServiceConnected(ComponentName className,        IBinder service) {      // Connecting to a secondary interface is the same as any      // other interface.      mSecondaryService = ISecondary.Stub.asInterface(service);      mKillButton.setEnabled(true);    }    public void onServiceDisconnected(ComponentName className) {      mSecondaryService = null;      mKillButton.setEnabled(false);    }  };  private OnClickListener mBindListener = new OnClickListener() {    public void onClick(View v) {      // Establish a couple connections with the service, binding      // by interface names. This allows other applications to be      // installed that replace the remote service by implementing      // the same interface.      Intent intent = new Intent(Binding.this, RemoteService.class);      intent.setAction(IRemoteService.class.getName());      bindService(intent, mConnection, Context.BIND_AUTO_CREATE);      intent.setAction(ISecondary.class.getName());      bindService(intent, mSecondaryConnection, Context.BIND_AUTO_CREATE);      mIsBound = true;      mCallbackText.setText("Binding.");    }  };  private OnClickListener mUnbindListener = new OnClickListener() {    public void onClick(View v) {      if (mIsBound) {        // If we have received the service, and hence registered with        // it, then now is the time to unregister.        if (mService != null) {          try {            mService.unregisterCallback(mCallback);          } catch (RemoteException e) {            // There is nothing special we need to do if the service            // has crashed.          }        }        // Detach our existing connection.        unbindService(mConnection);        unbindService(mSecondaryConnection);        mKillButton.setEnabled(false);        mIsBound = false;        mCallbackText.setText("Unbinding.");      }    }  };  private OnClickListener mKillListener = new OnClickListener() {    public void onClick(View v) {      // To kill the process hosting our service, we need to know its      // PID. Conveniently our service has a call that will return      // to us that information.      if (mSecondaryService != null) {        try {          int pid = mSecondaryService.getPid();          // Note that, though this API allows us to request to          // kill any process based on its PID, the kernel will          // still impose standard restrictions on which PIDs you          // are actually able to kill. Typically this means only          // the process running your application and any additional          // processes created by that app as shown here; packages          // sharing a common UID will also be able to kill each          // other's processes.          Process.killProcess(pid);          mCallbackText.setText("Killed service process.");        } catch (RemoteException ex) {          // Recover gracefully from the process hosting the          // server dying.          // Just for purposes of the sample, put up a notification.          Toast.makeText(Binding.this,              R.string.remote_call_failed,              Toast.LENGTH_SHORT).show();        }      }    }  };  // ----------------------------------------------------------------------  // Code showing how to deal with callbacks.  // ----------------------------------------------------------------------  /**  * This implementation is used to receive callbacks from the remote  * service.  */  private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {    /**    * This is called by the remote service regularly to tell us about    * new values. Note that IPC calls are dispatched through a thread    * pool running in each process, so the code executing here will    * NOT be running in our main thread like most other things -- so,    * to update the UI, we need to use a Handler to hop over there.    */    public void valueChanged(int value) {      mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));    }  };  private static final int BUMP_MSG = 1;  private Handler mHandler = new Handler() {    @Override public void handleMessage(Message msg) {      switch (msg.what) {        case BUMP_MSG:          mCallbackText.setText("Received from service: " + msg.arg1);          break;        default:          super.handleMessage(msg);      }    }  };

}

AIDL(Android界面定义语言)相似,你可能已经使用过其他的IDL。它允许您定义的编程接口,客户端和服务,才能与对方使用进程间通信(IPC)进行通信商定。在Android上,一个进程无法正常访问另一个进程的内存。所以讲,他们需要自己的对象分解成原语操作系统能够理解,马歇尔跨边界的对象为您服务。要做到这一点编组的代码是繁琐的编写,因此Android与AIDL为您代劳。

注意:使用AIDL是必要的前提是你让来自不同应用程序的客户端访问服务的IPC,并希望在处理你的服务多线程。如果你不需要在不同的应用程序执行并发IPC,你应该创建界面实现活页夹,或者,如果要执行IPC,但并不需要处理多线程,实现你的界面使用Messenger的。无论如何,请确保您了解绑定服务实现一个AIDL之前。

在你开始设计AIDL接口,要知道是直接的函数调用,调用一个AIDL接口。你不应该对其中调用发生线程的假设。根据呼叫是否来自本地进程中的线程或远程进程会发生什么事是不同的。特别:

  • 从本地工艺制成的呼叫在正在呼叫的同一个线程执行。如果这是你的主UI线程,该线程将继续在AIDL接口来执行。如果它是另一个线程,即,在服务执行代码中的之一。因此,如果只是本地线程访问该服务,可以完全哪些线程中执行它(但如果是这样的话,那么你不应该在所有使用AIDL控制,但应改为创建接口实现一个活页夹)。
  • 从远程进程调用从一个线程池的平台,自己的过程内保持调度。必须从未知线程来电,具有多个呼叫同时发生来制备。换句话说,一个AIDL接口的实现必须完全线程安全。
  • 单向关键字改变远程调用的行为。在使用时,一个远程调用不会阻塞;它只是发送的交易数据,并立即返回。的接口的实现最终接收该从常规呼叫粘合剂线程池作为正常远程调用。如果单向与本地电话使用的,不存在影响和通话仍然是同步的。

定义一个AIDL接口

您必须确定您的AIDL接口在.aidl使用Java编程语言的语法文件,然后将其保存在源代码(在SRC /目录下)这两个应用托管服务,并结合该服务的任何其他应用程序。

当你建立一个包含每个应用程序.aidl文件时,Android SDK工具生成的IBinder基于接口.aidl文件并将其保存在项目的根/目录下。该服务必须实现的IBinder接口为宜。然后,客户端应用程序绑定到从服务和调用方法的IBinder执行IPC。

要使用AIDL有界服务,请按照下列步骤操作:

  1. 创建.aidl文件

    该文件定义了方法签名的编程接口。

  2. 实现接口

    在Android SDK工具生成的Java编程语言的界面,根据您的.aidl文件。这个接口有一个内部抽象类名为存根扩展粘结剂并实现从你的AIDL接口中的方法。您必须扩展存根类,并实现方法。

  3. 公开接口给客户

    实施服务,并覆盖onBind()来回报您的实施存根类。

注意:您对您的AIDL接口的先放后的任何修改必须保留,以避免破坏使用你的服务的其他应用程序向后兼容。也就是说,因为你.aidl文件必须为了他们访问您的服务的接口,你必须保持原有的接口支持被复制到其他应用程序。

1.创建.aidl文件

AIDL使用一个简单的语法,它允许您声明一个接口,可以采取参数和返回值的一种或多种方法。的参数和返回值可以是任何类型的,即使是其他的AIDL生成接口。

您必须构建.aidl使用Java编程语言文件。每个.aidl文件必须定义一个接口,只需要接口声明和方法签名。

默认情况下,AIDL支持以下数据类型:

  • 所有原始类型的Java编程语言(如INT焦炭布尔,等等)
  • 为CharSequence
  • 名单

    在所有的元素列表必须在此列表中支持的数据类型之一,或者您已经声明了其他AIDL生成的接口或Parcelables并之一。一个列表可以选择作为“通用”类(例如,名单<String>的)。认为对方收到实际的具体类始终是一个ArrayList中,虽然会产生使用方法列表界面。

  • 地图

    在所有元素地图必须在此列表中支持的数据类型之一,或者您已经声明了其他AIDL生成的接口或Parcelables并之一。通用图,(如那些形式的地图<字符串,整数>不被支持。认为对方收到实际的具体类始终是一个HashMap中,虽然会产生使用方法地图界面。

您必须包括进口以上未列出的其他每个类型的语句,即使他们在同一个包为你的接口定义。

在定义服务接口,请注意:

  • 方法可以采取零个或多个参数,并返回一个值或空隙。
  • 所有非基本参数要求定向标记指示数据去哪个方向。无论是,或INOUT(见下面的例子)。

    原语是默认情况下,不能以其他方式。

    注意:您应该限制的方向是什么真正需要的,因为编组参数是昂贵的。

  • 包括在所有代码的注释.aidl文件都包含在生成的IBinder接口(除进口和包语句之前的评论)。
  • 只有方法的支持;你不能揭露AIDL静态字段。

下面是一个例子.aidl文件:

// IRemoteService.aidl 融为一体例如机器人; //此处声明任何非默认类型的import语句/ **示例服务接口* / 接口 IRemoteService  {   / **要求这项服务的进程ID,做坏事用它。* /   INT GETPID ();   / **表明可以作为参数使用一些基本类型  。*在AIDL返回值  * /   无效basicTypes INT ANINT  一起 布尔aBoolean  漂浮水上      aDouble  字符串ASTRING ) ; }

只需保存.aidl文件在项目的的src /目录下,当你建立你的应用程序,SDK工具生成的IBinder在项目的接口文件根/目录下。所生成的文件名 ​​相匹配的.aidl文件名 ​​,但是具有的.java扩展名(例如,IRemoteService.aidl导致IRemoteService.java)。

如果你使用Android工作室,增量构建几乎立即产生粘合剂类。如果你不使用Android工作室,那么摇篮工具生成构建应用程序,你应该建立与项目粘合剂类下一次gradle这个assembleDebug(或gradle这个assembleRelease只要你写完).aidl文件,所以你的代码可以对链接生成的类。

2.实现接口

当你建立你的应用程序时,Android SDK工具生成的.java您的名字命名的接口文件.aidl文件。生成的接口包括一个名为子类存根这是一个抽象实现其父接口(例如,YourInterface.Stub),并声明所有从方法.aidl文件。

注:存根还定义了一些辅助方法,最值得注意的是asInterface(),它接受一个的IBinder(通常是一个传递给客户的onServiceConnected()回调方法)并返回存根接口的一个实例。请参见调用一个IPC方法为如何使这个转换的更多细节。

为了实现从所产生的界面.aidl,延长所生成的粘合剂的接口(例如,YourInterface.Stub)并实施从继承的方法.aidl文件。

这里是称为界面的示例实施IRemoteService(由定义的IRemoteService.aidl使用匿名实例例如,上文):

private  final  IRemoteService . Stub mBinder =  new  IRemoteService . Stub ()  {   public  int getPid (){     return  Process . myPid ();   }   public  void basicTypes ( int anInt ,  long aLong ,  boolean aBoolean ,     float aFloat ,  double aDouble ,  String aString )  {     //不执行任何操作  } };

现在mBinder是的一个实例存根类(粘合剂),其定义了服务的RPC接口。在下一步骤中,这种情况下被暴露于客户端,这样他们可以与服务进行交互。

还有,你应该知道你的实现AIDL接口时,一些规则:

  • 呼入电话无法保证会在主线程上执行的,所以你需要考虑从一开始多线程和正确建立服务是线程安全的。
  • 默认情况下,RPC调用是同步的。如果您知道该服务需要超过几毫秒的时间来完成一个请求,你不应该从活动的主线程中调用它,因为它可能会挂起应用(Android版可能会显示一个“应用程序没有响应”对话框) - 你应该通常在客户端一个单独的线程调用它们。
  • 没有你抛出异常发送回调用者。

3.公开接口给客户

一旦你实现的接口为您服务,您需要将其暴露给客户,使他们能够绑定到它。揭露为您服务的接口,扩展服务并实现onBind()返回类实现所产生的一个实例存根(如上一节中讨论)。下面是一个公开的例子服务IRemoteService例如接口给客户。

                           返回                                                    不执行任何操作    }   }; }

现在,当一个客户端(如活动)调用bindService()来连接到该服务,客户端的onServiceConnected()回调接收mBinder由服务的返回的实例onBind()方法。

客户端还必须能够访问的接口类,因此,如果在客户端和服务都在独立的应用程序,则在客户端的应用程序必须具有的副本.aidl在其文件的src /目录(它产生android.os.Binder接口-提供给AIDL方法,客户端访问)。

当客户端收到的IBinderonServiceConnected()回调,它必须调用YourServiceInterface.Stub.asInterface(服务)将返回参数转换为YourServiceInterface类型。例如:

IRemoteService mIRemoteService ; 私人 ServiceConnection mConnection =   ServiceConnection () {   //当与服务建立连接调用  公共 无效onServiceConnected 组件名的className  的IBinder 服务 {     //按照上面一个AIDL接口的例子,    //这得 ​​到一个在IRemoteInterface,我们可以用它来 ​​在服务调用的实例    mIRemoteService =  IRemoteService 存根asInterface 服务  }   //调用时与服务的连接意外断开  公共 无效onServiceDisconnected 组件名的className  {     日志Ë TAG  “服务意外中断” );     mIRemoteService =  ;   } };

欲了解更多示例代码,请参见RemoteService.java类ApiDemos。

传递对象超过IPC

如果你有,你想通过IPC接口从一个进程发送到另一个类,你可以做到这一点。但是,你必须确保你的类的代码可到IPC通道的另一边,你的类必须支持Parcelable接口。支持Parcelable接口很重要,因为它可以让Android系统分解物进入,可以跨进程编组元。

要创建支持类Parcelable协议,必须做到以下几点:

  1. 让你的类实现Parcelable接口。
  2. 实施writeToParcel,这需要对象的当前状态,并把它写入到一个
  3. 一个叫做静态字段添加CREATOR到您的类,这是实现一个对象Parcelable.Creator接口。
  4. 最后,创建一个.aidl声明你parcelable类(如图所示的文件Rect.aidl文件,下同)。

    如果您使用的是自定义生成过程中,千万不能添加.aidl文件到您的构建。类似于C语言的头文件,这.aidl文件不被编译。

AIDL使用这些方法和字段在它生成于编组和解组的对象的代码。

例如,这里是一个Rect.aidl文件来创建一个矩形类的parcelable:

包装机器人图形; //声明矩形这样AIDL可以找到它,知道它实现//将parcelable协议。parcelable 矩形;

这里是该怎么一个例子矩形类实现Parcelable协议。

import android . os . Parcel ; import android . os . Parcelable ; public  final  class  Rect  implements  Parcelable  {   public  int left ;   public  int top ;   public  int right ;   public  int bottom ;   public  static  final  Parcelable . Creator < Rect > CREATOR =  new Parcelable . Creator < Rect >()  {     public  Rect createFromParcel ( Parcel  in )  {       return  new  Rect ( in );     }     public  Rect [] newArray ( int size )  {       return  new  Rect [ size ];     }   };   public  Rect ()  {   }   private  Rect ( Parcel  in )  {     readFromParcel ( in );   }   public  void writeToParcel ( Parcel  out )  {     out . writeInt ( left );     out . writeInt ( top );     out . writeInt ( right );     out . writeInt ( bottom );   }   public  void readFromParcel ( Parcel  in )  {     left =  in . readInt ();     top =  in . readInt ();     right =  in . readInt ();     bottom =  in . readInt ();   } }

在编组矩形类是非常简单的。看看在其他的方法包裹看到其他类型的值,你可以写一个包裹。

警告:不要忘记其他进程接收数据的安全问题。在这种情况下,矩形读取四个数字包裹,但它是由你来确保,这些是任何呼叫者正试图做的值的可接受的范围内。见安全和权限有关如何保证应用程序的安全免受恶意软件的更多信息。

调用一个IPC方法

这里有一个调用的类必须调用与AIDL定义的远程接口的步骤:

  1. 包括.aidl在项目文件中的src /目录下。
  2. 声明的一个实例的IBinder接口(生成基于所述AIDL)。
  3. 实施ServiceConnection
  4. 呼叫Context.bindService(),并传入您的ServiceConnection实现。
  5. 在你执行onServiceConnected(),您将收到的IBinder实例(称为服务)。呼叫YourInterfaceName.Stub.asInterface((的IBinder)服务将返回的参数强制转换为YourInterface类型。
  6. 请致电您在接口上定义的方法。你应该总是陷阱DeadObjectException异常,当连接中断而抛出;这将是由远程方法抛出的唯一例外。
  7. 要断开连接,调用Context.unbindService()与接口的实例。

在调用一个IPC服务需要注意几点:

  • 对象引用跨进程计数。
  • 您可以发送匿名对象作为方法的参数。

有关绑定到服务的更多信息,请阅读绑定服务文档。

下面是一些示例代码演示调用一个AIDL创建的服务,从项目ApiDemos远程服务取试样。

公共 静态  绑定 扩展 活动 {   / **主界面,我们将在服务调用进行。* /   IRemoteService MSERVICE =  ;   / **我们使用该服务的另一个接口。              本次活动的标准初始化。设置UI,然后等待  *为用户做之前,它捅               留意按钮         附“ );   }   / **   *分类为与所述主界面交互                           这与该服务的连接已被调用时      //建立,使我们的服务对象,我们可以用它来      ​​//使用服务进行交互。我们正在与我们沟通      ,通过IDL接口//服务,因此得到了客户端      //从原始服务的代表        我们想监控,只要我们的服务      //连接到它。      尝试 {         MSERVICE registerCallback mCallback );       }  赶上 RemoteException的ē  {         //在这种情况下,我们可能甚至在服务已经崩溃        //做与任何东西,我们可以指望很快被        //断开(然后重新连接,如果可以重新启动)        //所以没有必要做任何事情在这里。      }       //由于样本的一部分,告诉用户什么                                 这就是所谓的当与服务的连接已      //意外断开-也就是说,它的进程崩溃。      MSERVICE =  ;       mKillButton 的setEnabled ​​假);       mCallbackText 的setText “断开” );       //作为一部分样本,告诉用户什么                           类具有的二级界面进行交互                           连接到辅助接口是相同的任何      //其他                                     与该服务建立了几个连接,结合      由接口名称//这允许其它应用程序是      //装通过实施替换远程服务      //相同                                               如果我们收到了该服务,因此与注册        //它,那么现在是注销的时间        ,如果 MSERVICE !=   {           尝试 {             MSERVICE unregisterCallback mCallback ;)          }  赶上 RemoteException的ē  {             //有没什么特别的,我们需要做的,如果服务            //已崩溃。          }         }         //分离我们现有的                                杀死进程托管我们的服务,我们需要知道它      // PID。我们的便利服务,具有呼叫,将返回      //给我们的信息。      如果 mSecondaryService !=   {         尝试 {           INT PID = mSecondaryService GETPID ( );           //需要注意的是,虽然该API允许我们请求          //杀根据它的PID任何进程,内核会          //仍然征收标准限制它的PID你          //居然能够杀死通常,这意味着只。          //运行应用程序和任何其他的过程          由应用程序创建//流程如下图所示;包          //共用一个UID也能自相残杀          。//其他的流程          过程killProcess PID );           mCallbackText 的setText “杀了服务流程。” );         }  赶上 RemoteException的 {           //从托管过程中恢复正常          。//服务器垂死          //只为样本的目的,提出了一个                                               -------------------------------------------------- --------------------   //显示如何处理回调代码。  // ------------------ -------------------------------------------------- -   / **   *这种实现用于从远程接收回调  *服务。  * /   私人 IRemoteServiceCallback mCallback =   IRemoteServiceCallback 存根() {     / **     *这是由远程服务名为定期向我们讲述    *新。值的注意的是IPC调用都是通过一个线程进行调度    的每个进程中运行*池,所以这里执行的代码将    *不是我们最喜欢的其他东西主线程中运行-因此,    *更新UI,我们需要使用一个Handler来跃过                                                 从服务:“  + 味精ARG1 );           打破;         默认          的handleMessage 味精);       }     }   }; }

更多相关文章

  1. android intent的常用方法
  2. Android如何查找应用中调用的系统资源
  3. android webview 使用详细介绍
  4. android native c++ thread
  5. Android调用系统应用程序
  6. android
  7. android > android 客户端 ,PHP 服务器端 HttpGet类和HttpPost类
  8. Android(安卓)IPC 通讯机制源码分析 二
  9. Android(安卓)中Service生命周期

随机推荐

  1. Android(安卓)View 如何去自定义View
  2. [置顶] Android短信息验证码自动填写详细
  3. Android(安卓)开发 —— Handler的使用
  4. Android的界面设计规范-5
  5. Android(安卓)APK安装后点击[打开]与[完成]的
  6. Android中asset文件夹和raw文件夹区别
  7. Android学习之Activity伪装成对话框形式)
  8. Flutter 插件开发:以微信SDK为例
  9. Delphi XE7下如何创建一个Android模拟器
  10. 谷歌Android碎片化严重:Android4.0份额仅