`

Android Interface Definition Language(AIDL)

 
阅读更多

<!-- [if gte mso 9]><xml><w:WordDocument><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel><w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery><w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery><w:DocumentKind>DocumentNotSpecified</w:DocumentKind><w:DrawingGridVerticalSpacing>7.8</w:DrawingGridVerticalSpacing><w:View>Normal</w:View><w:Compatibility></w:Compatibility><w:Zoom>0</w:Zoom></w:WordDocument></xml><![endif]-->

使用AIDL 设计远程接口 ( Designing a Remote Interface Using AIDL )

由于每个应用程序都运行在自己的进程空间,并且可以从应用程序UI 运行另一个服务进程,而且经常会在不同的进程间传递对象。在 Android 平台,一个进程通常不能访问另一个进程的内存空间,所以要想对话,需要将对象分解成操作系统可以理解的基本单元,并且有序的通过进程边界。

通过代码来实现这个数据传输过程是冗长乏味的,Android 提供了 AIDL 工具来处理这项工作。

AIDL (Android Interface Definition Language)是一种 IDL  语言,用于生成可以在 Android 设备上两个进程之间进行进程间通信 (IPC) 的代码。如果在一个进程中(例如 Activity )要调用另一个进程中(例如 Service )对象的操作,就可以使用 AIDL 生成可序列化的参数。

AIDL IPC机制是面向接口的,像 COM Corba 一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。

 

使用AIDL 实现 IPC( Implementing IPC Using AIDL )

使用AIDL 实现 IPC 服务的步骤是:

1.  创建.aidl 文件 - 该文件( YourInterface.aidl )定义了客户端可用的方法和数据的接口。

2.  makefile 文件中加入 .aidl 文件 - Eclipse 中的 ADT 插件提供管理功能) Android 包括名为 AIDL 的编译器,位于 tools/ 文件夹。

3.  实现接口-AIDL 编译器从 AIDL 接口文件中利用 Java 语言创建接口,该接口有一个继承的命名为 Stub 的内部抽象类(并且实现了一些 IPC 调用的附加方法),要做的就是创建一个继承于 YourInterface.Stub 的类并且实现在 .aidl 文件中声明的方法。

4.  向客户端公开接口- 如果是编写服务,应该继承 Service 并且重载 Service.onBind(Intent)  以返回实现了接口的对象实例

 

创建.aidl 文件 ( Create an .aidl File )

AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。这些参数和返回值可以是任何类型,甚至是其他 AIDL 生成的接口。重要的是必须导入所有非内置类型,哪怕是这些类型是在与接口相同的包中。下面是 AIDL 能支持的数据类型:

Java编程语言的主要类型  (int, boolean — 不需要  import  语句。

以下的类 ( 不需要 import  语句 ):

String

List  - 列表中的所有元素必须是在此列出的类型,包括其他AIDL 生成的接口和可打包类型。 List 可以像一般的类(例如 List<String> )那样使用,另一边接收的具体类一般是一个 ArrayList ,这些方法会使用 List 接口。

Map  -  Map中的所有元素必须是在此列出的类型,包括其他 AIDL 生成的接口和可打包类型。一般的 maps (例如 Map<String,Integer> )不被支持,另一边接收的具体类一般是一个 HashMap ,这些方法会使用 Map 接口。

CharSequence  - 该类是被TextView 和其他控件对象使用的字符序列。

通常引引用方式传递的其他AIDL 生成的接口,必须要 import  语句声明

实现了Parcelable protocol  以及按值传递的自定义类,必须要 import  语句声明。

以下是基本的AIDL 语法:

,

 

实现接口( Implementing the Interface )

AIDL生成了与 .aidl 文件同名的接口,如果使用 Eclipse 插件, AIDL 会做为编译过程的一部分自动运行(不需要先运行 AIDL 再编译项目),如果没有插件,就要先运行 AIDL

生成的接口包含一个名为Stub 的抽象的内部类,该类声明了所有 .aidl 中描述的方法, Stub 还定义了少量的辅助方法,尤其是 asInterface() ,通过它或以获得 IBinder (当 applicationContext.bindService() 成功调用时传递到客户端的 onServiceConnected() )并且返回用于调用 IPC 方法的接口实例,更多细节参见 Calling an IPC Method

要实现自己的接口,就从YourInterface.Stub 类继承,然后实现相关的方法(可以创建 .aidl 文件然后实现 stub 方法而不用在中间编译, Android 编译过程会在 .java 文件之前处理 .aidl 文件)。

这个例子实现了对IRemoteService 接口的调用,这里使用了匿名对象并且只有一个 getPid() 接口。

这里是实现接口的几条说明:

不会有返回给调用方的异常

默认IPC 调用是同步的。如果已知 IPC 服务端会花费很多毫秒才能完成,那就不要在 Activity View 线程中调用,否则会引起应用程序挂起( Android 可能会显示“应用程序未响应”对话框),可以试着在独立的线程中调用。

AIDL接口中只支持方法,不能声明静态成员。

 

向客户端暴露接口( Exposing Your Interface to Clients )

在完成了接口的实现后需要向客户端暴露接口了,也就是发布服务,实现的方法是继承 Service ,然后实现以 Service.onBind(Intent) 返回一个实现了接口的类对象。下面的代码片断表示了暴露 IRemoteService 接口给客户端的方式。

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 ;

     }

 

     /**

     * 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 );

         }

     };

 

     /**

     * A secondary interface to the service.

     */

     private   final   ISecondary . Stub  mSecondaryBinder  =   new   ISecondary . Stub ()   {

         public   int  getPid ()   {

             return   Process . myPid ();

         }

         public   void  basicTypes ( int  anInt ,   long  aLong ,   boolean  aBoolean ,

                 float  aFloat ,   double  aDouble ,   String  aString )   {

         }

     };

 

}

 

使用可打包接口传递参数 Pass by value Parameters using Parcelables

如果有类想要能过AIDL 在进程之间传递,这一想法是可以实现的,必须确保这个类在 IPC 的两端的有效性,通常的情形是与一个启动的服务通信。

这里列出了使类能够支持Parcelable 4 个步骤:【译者注:原文为 5 ,但列表为 4 项,疑为作者笔误】

1.  使该类实现Parcelabel 接口。

2.  实现public void writeToParcel(Parcel out)  方法,以便可以将对象的当前状态写入包装对象中。

3.  增加名为CREATOR 的构造器到类中,并实现 Parcelable.Creator 接口。

4.  最后,但同样重要的是,创建AIDL 文件声明这个可打包的类(见下文),如果使用的是自定义的编译过程,那么不要编译此 AIDL 文件,它像 C 语言的头文件一样不需要编译。

AIDL会使用这些方法的成员序列化和反序列化对象。

这个例子演示了如何让Rect 类实现 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 ();

}

}

这个是Rect.aidl 文件。

序列化Rect 类的工作相当简单,对可打包的其他类型的数据可以参见 Parcel 类。

警告 :不要忘了对从其他进程接收到的数据进行安全检查。在上面的例子中,rect 要从数据包中读取 4 个数值,需要确认无论调用方想要做什么,这些数值都是在可接受的范围之内。想要了解更多的关于保持应用程序安全的内容,可参见  Security and Permissions

 

调用IPC 方法 (Calling an IPC Method)

这里给出了调用远端接口的步骤:

1.  声明.aidl 文件中定义的接口类型的变量。

2.  实现ServiceConnection

3.  调用Context.bindService() ,传递 ServiceConnection 的实现

4.  ServiceConnection.onServiceConnected() 方法中会接收到 IBinder 对象,调用 YourInterfaceName.Stub.asInterface((IBinder)service) 将返回值转换为 YourInterface 类型

5.  调用接口中定义的方法。应该总是捕获连接被打断时抛出的DeadObjectException 异常,这是远端方法唯一的异常。

6.  调用Context.unbindService() 断开连接

这里是几个调用IPC 服务的提示:

对象是在进程间进行引用计数

可以发送匿名对象作为方法参数

以下是演示调用AIDL 创建的服务,可以在 ApiDemos 项目中获取远程服务的示例。

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.

       bindService ( new   Intent ( IRemoteService . class . getName ()),

              mConnection ,   Context . BIND_AUTO_CREATE );

            bindService ( new   Intent ( ISecondary . class . getName ()),

             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 );

         }

    }

};

}

 

 

原文 <!-- [if gte mso 9]><xml><w:WordDocument><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel><w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery><w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery><w:DocumentKind>DocumentNotSpecified</w:DocumentKind><w:DrawingGridVerticalSpacing>7.8</w:DrawingGridVerticalSpacing><w:View>Normal</w:View><w:Compatibility></w:Compatibility><w:Zoom>0</w:Zoom></w:WordDocument></xml><![endif]-->

http://developer.android.com/guide/developing/tools/a idl .html  ( 注意:3.0 r1  以后移到 Appendix )

 

分享到:
评论

相关推荐

    AIDL示例(Android Interface Definition Language)

    为了使其他的应用程序也可以访问本应用程序...因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。博客地址:http://blog.csdn.net/u013293125/article/details/77368261

    Android项目之AidlDemo(简单aidl的例子)

    Android项目之AidlDemo(简单的aidl的例子)。AIDL是Android中IPC(Inter-Process Communication)方式中的一种,AIDL是Android Interface definition language的缩写。需要的小伙伴自请下载。

    Android 2.3 r1开发者指南——AIDL

    AIDL,即Android Interface Definition Language,是Android系统中用于跨进程通信(Inter-Process Communication,IPC)的一种接口定义语言。由于Android系统设计中,每一个应用程序都运行在其独立的进程中,这导致...

    Android多进程通讯AIDL传递Parcelable对象

    AIDL(Android Interface Definition Language)是Android提供的一种接口定义语言,用于支持跨进程调用方法,从而实现多进程间的通信。 AIDL的基本原理是将接口定义为一个.aidl文件,系统会自动生成对应的Java代码...

    AIDL最简单的使用步骤

    AIDL:Android Interface Definition Language,即Android接口定义语言。 为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他...

    AndroidAIDL

    **Android AIDL(Android Interface Definition Language)详解** 在Android系统中,进程间的通信(IPC, Inter-Process Communication)是至关重要的,特别是在开发大型、复杂的应用时。AIDL(Android Interface ...

    Android多进程通讯AIDLDemo

    Android Aidl(Android Interface Definition Language)是一种专门为Android系统设计的接口定义语言,它允许我们在不同的Android进程间实现安全、高效的通信。 标题"Android多进程通讯AIDLDemo"指出我们将探讨如何...

    android studio下使用aidl接口传递自定义对象

    在Android开发中,有时我们需要在不同的进程间进行通信,这时我们可以使用Android Interface Definition Language (AIDL)。AIDL提供了一种机制,使得Android应用能够跨进程传递数据,包括自定义对象。本文将深入探讨...

    安卓AIDL相关-androidstudio下使用aidl接口传递自定义对象.rar

    在Android开发中,AIDL(Android Interface Definition Language)是一种强大的工具,用于实现进程间通信(IPC,Inter-Process Communication)。AIDL使得不同Android进程中的组件能够互相调用方法,即便它们运行在...

    Android的IPC与AIDL

    #### 三、AIDL(Android Interface Definition Language) **1. AIDL介绍:** AIDL是一种用于定义进程间通信接口的语言。使用AIDL可以定义一个接口文件(通常以.aidl为后缀),这个文件描述了远程接口的行为,包括...

    android AidlDemo(简单aidl的例子)

    在Android开发中,AIDL(Android Interface Definition Language)是一种用于进程间通信(Inter-Process Communication, IPC)的工具,使得不同应用之间的服务可以共享数据和功能。本示例"android AidlDemo(简单aidl...

    个人练习android md5加密和aidl通信demo

    在Android开发中,MD5加密和AIDL(Android Interface Definition Language)通信是两个重要的技术概念。MD5是一种广泛使用的加密散列函数,而AIDL则是Android系统中用于进程间通信(IPC)的一种机制。 首先,让我们...

    Android深入理解分析Aidl调用作业流程.docx

    Android深入理解分析Aidl调用作业流程是Android开发中的一项重要技术,Aidl(Android Interface Definition Language)是Android提供的一种接口定义语言,用于描述Android系统中服务端和客户端之间的接口。...

    androidstudio开发的aidl小demo

    在Android应用开发中,AIDL(Android Interface Definition Language)是一种重要的工具,用于实现跨进程通信(IPC, Inter-Process Communication)。本教程将基于"androidstudio开发的aidl小demo"来详细讲解AIDL的...

    android开发使用aidl进行跨进程通信demo

    Android Interface Definition Language(AIDL)是Android提供的一种原生接口,它允许开发者定义服务接口,使得其他进程可以调用这些服务,实现跨进程通信。本教程将深入讲解如何使用AIDL在Android开发中构建一个...

    android aidl 本地和aidl通信,远端和aidl

    在Android平台上,应用程序间通信(IPC,Inter-Process Communication)是一项关键的技术,而Android Interface Definition Language(AIDL)就是Android系统提供的一种强大的工具,用于实现进程间的通信。...

    AIDL List传递 String传递(android studio)

    这时,Android Interface Definition Language (AIDL) 就派上用场了。AIDL 是 Android 提供的一种接口定义语言,用于创建进程间的接口,使得不同进程间可以安全、有效地交换数据。在这个"AIDL List传递 String传递...

    Android Service讲解 和 aidl 实现

    在Android应用开发中,`Service`和`AIDL(Android Interface Definition Language)`是两个非常重要的组件,它们分别用于后台长时间运行的任务和服务间通信。本文将深入探讨这两个概念以及如何通过`AIDL`来实现服务...

    Android Studio实现Service AIDL

    为使应用程序之间能够彼此通信,Android提供了IPC (Inter Process Communication,进程间通信)的一种独特实现: AIDL (Android Interface Definition Language, Android接口定义语言)。 建立两个Android项目,...

    AIDL和JNI使用的小例子

    **Android Interface Definition Language (AIDL)** AIDL是Android中用于进程间通信(IPC, Inter-Process Communication)的一种工具,它允许你在不同的Android进程之间定义和实现接口。当你需要在一个应用组件...

Global site tag (gtag.js) - Google Analytics