zoukankan      html  css  js  c++  java
  • Android AIDL的用法

    一、什么是AIDL服务

       一般创建的服务并不能被其他的应用程序访问。为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。 

    二、AIDL基本语法 

      AIDL使用简单的语法来声明接口,描述其方法以及方法的参数和返回值。这些参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。
      其中对于Java编程语言的基本数据类型 (int, long, char, boolean,String,CharSequence)集合接口类型List和Map,不需要import 语句。
      而如果需要在AIDL中使用其他AIDL接口类型,需要import,即使是在相同包结构下。AIDL允许传递实现Parcelable接口的类,需要import
      需要特别注意的是,对于非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。

      AIDL只支持接口方法,不能公开static变量。 

    三、android应用层使用AIDL

    3.1、简要步骤

      1、在Eclipse Android工程的Java包目录中建立一个扩展名为A.aidl的文件,并写下需要的接口。如果aidl文件的内容是正确的,ADT会在gen目录下自动生成一个A.Java接口文件。
      2、建立一个服务类(Service的子类)。并在创建的服务类中创建一个内部类,实现由aidl文件生成的Java接口。
      3、在服务类的onBind方法返回时,将实现aidl接口的内部类对象返回出去。
      4、在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类的参数值。

    3.2、具体操作

    3.2.1、创建文件IMyService.aidl: 

            
      文件内容:

    1. package du.pack;  
    2. interface IMyService{  
    3.     //只有一个接口  
    4.     String getValue();  
    5. }   

    3.2.2、创建服务类及实现内部类

    1. public class MyService extends Service {  
    2.   
    3.     @Override  
    4.     public IBinder onBind(Intent arg0) {  
    5.         // 把内部类的对象返回给客户端使用  
    6.         return new MyServiceImpl();  
    7.     }  
    8.   
    9.     // 创建一个继承自IMyService.Stub的内部类  
    10.     public class MyServiceImpl extends IMyService.Stub {  
    11.   
    12.         // 必须实现AIDL文件中的接口  
    13.         public String getValue() throws RemoteException {  
    14.             return null;  
    15.         }  
    16.     }  
    17. }  

      注意,我们写的service中,onBind方法必须返回MyServiceImpl类的对象实例,否则客户端无法获得服务对象。

    3.2.3、在AndroidManifest.xml文件中配置MyService类

    1. <service android:name=".MyService" >  
    2.     <intent-filter>  
    3.         <action android:name="du.pack.IMyService" />  
    4.     </intent-filter>  
    5. </service>  

      上面的"du.pack.IMyService"是客户端用于访问AIDL服务的ID。 

    4、本地客户端的使用方法 

        4.1、新建一个Eclipse Android工程,并将刚才远程服务端自动生成的gen目录下面的IMyService.java文件连同包目录一起复制到客户端工程的src目录中。

            

     4.2、调用AIDL服务首先要绑定服务,然后才能获得服务对象。

    1. public class AidlClientTestActivity extends Activity {  
    2.     // 远程服务端的对象  
    3.     IMyService mIMyService;  
    4.     private ServiceConnection mConnection = new ServiceConnection() {  
    5.   
    6.         public void onServiceConnected(ComponentName name, IBinder service) {  
    7.             // 绑定成功,得到远程服务端的对象,目标完成!!!  
    8.             mIMyService = IMyService.Stub.asInterface(service);  
    9.         }  
    10.   
    11.         public void onServiceDisconnected(ComponentName name) {  
    12.             // 解除绑定  
    13.             mIMyService = null;  
    14.         }  
    15.   
    16.     };  
    17.   
    18.     @Override  
    19.     public void onCreate(Bundle savedInstanceState) {  
    20.         super.onCreate(savedInstanceState);  
    21.         setContentView(R.layout.main);  
    22.   
    23.         // 绑定远程服务端服务  
    24.         Intent serviceIntent = new Intent("du.pack.IMyService");  
    25.         bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);  
    26.     }  
    27. }  

    5、用法小结 

      回顾一下整个调用的过程:
      服务端方面:将需要开放的接口抽象到aidl文件中,然后在自己的内部类中对接口进行实现,并在自己被绑定的时候把内部类对象返回给客户端。
    客户端方面:当我们需要远程某个Service时,就像在绑定本地的Service一样去bindService,然后在绑定成功的回调函数中(也就是onServiceConnected方法)得到一个Ibinder对象(比如Service),这时调用IMyService.Stub.asInterface(service)这样的语句,就可以得到服务端开放的interface接口对象,此时客户端可以直接调用这个对象的方法,犹如直接调用远程的Service对象一般。

    四、Framework中使用AIDL

             Framework中使用AIDL我们通过ITelephonyRegistry这个SystemService进行分析。该服务的主要作用就是对通话相关的事件进行监听,我们重心放在AIDL的实现结构上,不去关注ITelephonyRegistry具体的实现。

    1、AIDL文件相关

            先来看一下这个服务的AIDL文件: 

     
    1. @ITelephonyRegistry.aidl  
    2. interface ITelephonyRegistry {  
    3.     void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);  
    4.     void notifyCallState(int state, String incomingNumber);  
    5.     void notifyServiceState(in ServiceState state);  
    6.     void notifySignalStrength(in SignalStrength signalStrength);  
    7.     void notifyMessageWaitingChanged(boolean mwi);  
    8. }  

            再来看这个服务的真正实现: 

     
    1. @TelephonyRegistry.java  
    2. class TelephonyRegistry extends ITelephonyRegistry.Stub {  
    3.     TelephonyRegistry(Context context) {  
    4.         ......  
    5.     }  
    6.     void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow){  
    7.         ......  
    8.     }  
    9.     void notifyCallState(int state, String incomingNumber){  
    10.         ......  
    11.     }  
    12.     void notifyServiceState(in ServiceState state){  
    13.         ......  
    14.     }  
    15.     void notifySignalStrength(in SignalStrength signalStrength){  
    16.         ......  
    17.     }  
    18.     void notifyMessageWaitingChanged(boolean mwi){  
    19.         ......  
    20.     }  
    21. }  

            上面的两个文件是这个服务的核心部分,aidl文件规定了这个服务的功能,而java文件是对功能的具体实现。但是,此时的TelephonyRegistry并没有继承Service的类,也就是说,当前他并不具备作为一个Service的资格。那么他是如何变成一个服务的呢?

         2、服务的注册过程

             在SystemService中可以找到答案。

    1. @SystemServer.java  
    2. class ServerThread extends Thread {  
    3.     @Override  
    4.     public void run() {  
    5.         try {  
    6.             telephonyRegistry = new TelephonyRegistry(context);  
    7.             ServiceManager.addService("telephony.registry", telephonyRegistry);  
    8.         }  
    9.     }  
    10. }  

            我们看到,在这一步中,把telephonyRegistry对象(也就是ITelephonyRegistry.Stub的子类对象)作为一个Service注册给了ServiceManager。并且注册的名字是“telephony.registry”
            有了这一步,TelephonyRegistry就可以作为服务提供者向客户端开放了。也就是说,有了这一步,TelephonyRegistry才算上是一个真正的Service,可以接受客户端的连接申请。

            那么接下来,我们怎么得到这个Service呢?

    3、如何得到注册的服务

            既然通过ServiceManager注册了服务,我们就需要再次通过ServiceManager得到它的服务对象。

    1. private ITelephonyRegistry sRegistry;  
    2. sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));  

            通过这样的方法,我们就得到了ITelephonyRegistry.aidl的对象sRegistry。

    4、流程总结

             回顾一下这种AIDL服务的框架:通过继承ITelephonyRegistry.Stub父类去实现AIDL中规定的接口,然后把TelephonyRegistry作为ServiceManager注册给SystemService。客户端可以通过ServiceManager得到TelephonyRegistry的对象,然后就可以去调用AIDL中定义的接口了。

     

  • 相关阅读:
    leetcode 673. 最长递增子序列的个数 java
    leetcode 148. 排序链表 java
    leetcode 98. 验证二叉搜索树 java
    leetcode 29. 两数相除 java
    leetcode 234. 回文链表 java
    Valid Palindrome LeetCode Java
    Single Number II LeetCode Java
    Single Number LeetCode java
    Search in Rotated Sorted Array II LeetCode Java
    Search in Rotated Sorted Array leetcode java
  • 原文地址:https://www.cnblogs.com/linghu-java/p/8794389.html
Copyright © 2011-2022 走看看