aidl使用以及bindService

转自:http://blog.csdn.net/yangzhaomuma/article/details/50576017


AIDL简义

Android中的数据传输、方法调用等,常见的是集中在应用程序内的Activity之间,如Activity-A传递到Activity-B。

这样的数据传输、方法等都是在一个应用程序间调用,也就是在一个进程内。那如果我们要在不同的进程间传递数据,我们要怎么做呢?不在同一个进程间,它们是无法共用内存的,Android为了实现进程间的数据共享,提供了AIDL机制(安卓远程接口定义语言)——(AIDL: Android Interface definition language)。

AIDL的原理以及原理分析,可参考网上其他的解释。

下文将主要介绍AIDL的各种修饰符(in、out、inout)以及类序列化Parcelable的使用示例(网上原理解释很多,但对out、inout的示例很少见到)。

AIDL的实现

AIDL的应用场景,一般情况下是有两个进程,一个进程提供方法,一个进程调用方法。

我们习惯将提供方法的进程定义为Service端、将调用方法的进程定义为Client,就是我们常说的AIDL服务端和AIDL客户端。

AIDL的数据传输支持类型有特殊要求,并非所有的数据类型都能像以往一样传递:

支持数据类型如下:
1. Java 的原生类型
2. String 和CharSequence
3. List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型;  以上三种类型都不需要导入(import)
4. AIDL 自动生成的接口  需要导入(import)
5. 实现android.os.Parcelable 接口的类.  需要导入(import)。 

那我们接下来演示,如何提供AIDL的服务端和客户端。

这里重点是in、out、inout修饰符以及Parcelable的使用!常见的是in、Parcelable,少用的out、inout。

这几种修饰符,可理解如下:

in:客户端的参数输入;

out:服务端的参数输入;

inout:这个可以叫输入输出参数,客户端可输入、服务端也可输入。客户端输入了参数到服务端后,服务端也可对该参数进行修改等,最后在客户端上得到的是服务端输出的参数。

AIDL的服务端(Service端)实现

常用做法:
1、定义一个AIDL接口,在该接口中写方法;
2、方法中参数修饰符可以是in、out、inout,也有自定义的类,该类需要实现Parcelable接口;
3、实现该接口;
4、开放给客户端一个标志,用于访问服务端接口方法。
按以上的三个步骤,我们来写下示例代码:
1、定义AIDL接口:
新建一个文件,文件名为IBase.aidl,内容为:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.aidl;  
  2. import com.example.aidl.UserInfo;//注意引用  
  3. interface IBase  
  4. {  
  5.      int    add(int i,int j);  
  6.      String getUserInfo(in UserInfo userinfo);  
  7.      void   getaList(out String[] list);    
  8.      void   setaList(in String[] list);  
  9.      void   gettList(inout String[] list);  
  10. }  
上方的接口中的方法,我们演示了各种修饰符以及Parcelable。
这里有个需要注意的地方,我们在文件头中有import一个类,这个是必要的,虽然UserInfo类和我们定义的接口是在同一个包下。
Parcelable的使用,我们首先要实现这个UserInfo的Parcelable接口实现,然后引用它,如下:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.aidl;  
  2.   
  3. import android.os.Parcel;  
  4. import android.os.Parcelable;  
  5.   
  6. public class UserInfo implements Parcelable{  
  7.   
  8.       
  9.     private String name;  
  10.     private String adress;  
  11.     private int  age;  
  12.       
  13.     /**  
  14.      * @return the name  
  15.      */  
  16.     public String getName() {  
  17.         return name;  
  18.     }  
  19.   
  20.     /**  
  21.      * @param name the name to set  
  22.      */  
  23.     public void setName(String name) {  
  24.         this.name = name;  
  25.     }  
  26.   
  27.     /**  
  28.      * @return the adress  
  29.      */  
  30.     public String getAdress() {  
  31.         return adress;  
  32.     }  
  33.   
  34.     /**  
  35.      * @param adress the adress to set  
  36.      */  
  37.     public void setAdress(String adress) {  
  38.         this.adress = adress;  
  39.     }  
  40.   
  41.     /**  
  42.      * @return the age  
  43.      */  
  44.     public int getAge() {  
  45.         return age;  
  46.     }  
  47.   
  48.     /**  
  49.      * @param age the age to set  
  50.      */  
  51.     public void setAge(int age) {  
  52.         this.age = age;  
  53.     }  
  54.   
  55.     @Override  
  56.     public int describeContents() {  
  57.         // TODO Auto-generated method stub  
  58.         return 0;  
  59.     }  
  60.   
  61.     @Override  
  62.     public void writeToParcel(Parcel dest, int flags) {  
  63.         // TODO Auto-generated method stub  
  64.         dest.writeString(name);  
  65.         dest.writeString(adress);  
  66.         dest.writeInt(age);  
  67.     }  
  68.      
  69.     public static final Parcelable.Creator<UserInfo> CREATOR=new Creator<UserInfo>() {  
  70.   
  71.         @Override  
  72.         public UserInfo createFromParcel(Parcel source) {  
  73.             // TODO Auto-generated method stub  
  74.             UserInfo userInfo=new UserInfo();  
  75.             userInfo.setName(source.readString());  
  76.             userInfo.setAdress(source.readString());  
  77.             userInfo.setAge(source.readInt());  
  78.             return userInfo;  
  79.         }  
  80.   
  81.         @Override  
  82.         public UserInfo[] newArray(int size) {  
  83.             // TODO Auto-generated method stub  
  84.             return new UserInfo[size];  
  85.         }  
  86.     };  
  87. }  
声明这个自定义类:
在同一个包下,创建一个UserInfo.aidl文件,内容如下:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.aidl;  
  2.   
  3. parcelable UserInfo;  

综合以上,在使用自定义类时,需要有几个步骤:
(1)实现Parcelable接口,具体过程可参考: http://blog.csdn.net/yangzhaomuma/article/details/50452651
(2)在同一包名下,创建类同名的AIDL文件;
(3)在使用该类时,需要在文件头引用(import)。
2、实现接口方法:
新建一个java文件,我们暂命名为:AIDLService.java,该文件是实现AIDL的接口。内容如下:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.aidl_server_csdn;  
  2.   
  3.   
  4. import com.example.aidl.IBase;  
  5. import com.example.aidl.UserInfo;  
  6. import android.app.Service;  
  7. import android.content.Intent;  
  8. import android.os.IBinder;  
  9. import android.os.RemoteException;  
  10.   
  11. public class AIDLService extends Service{  
  12.   
  13.     String info="";  
  14.     @Override  
  15.     public IBinder onBind(Intent intent) {  
  16.         // TODO Auto-generated method stub  
  17.         return stub;  
  18.     }  
  19.   
  20.     private IBase.Stub stub=new IBase.Stub() {  
  21.   
  22.         /**  
  23.          * 基本类型的使用示例  
  24.          */  
  25.         @Override  
  26.         public int add(int i, int j) throws RemoteException {  
  27.             // TODO Auto-generated method stub  
  28.             return i+j;  
  29.         }  
  30.         /**  
  31.          * Parcelable类userinfo的使用示例  
  32.          */  
  33.         @Override  
  34.         public String getUserInfo(UserInfo userinfo) throws RemoteException {  
  35.             // TODO Auto-generated method stub  
  36.             String resultString="name:"+userinfo.getName()+" "+"adress:"+userinfo.getAdress()+" "+"age:"+userinfo.getAge();  
  37.             return resultString;  
  38.         }  
  39.         /**  
  40.          * out修饰类型的使用  
  41.          * 表示服务端输入  
  42.          */  
  43.         @Override  
  44.         public void getaList(String[] list) throws RemoteException {  
  45.             // TODO Auto-generated method stub  
  46.             list[0]="服务端赋值信息:"+info;  
  47.         }  
  48.   
  49.         /**  
  50.          * inout修饰类型的使用示例  
  51.          */  
  52.         @Override  
  53.         public void gettList(String[] list) throws RemoteException {  
  54.             // TODO Auto-generated method stub  
  55.             String totalString="";  
  56.             /**  
  57.              * 从客户端取得的信息  
  58.              */  
  59.             String receviceFromClientString="";  
  60.             for(int i=0;i<list.length;i++)  
  61.             {  
  62.                 receviceFromClientString+=list[i];  
  63.             }  
  64.             /**  
  65.              * 从服务端返回的信息  
  66.              */  
  67.             totalString+="从客户端收到的信息为:"+receviceFromClientString+" \n在此我们新增一段返回信息:good";  
  68.             list[0]=totalString;  
  69.         }  
  70.         /**  
  71.          * in修饰类型的使用示例  
  72.          */  
  73.         @Override  
  74.         public void setaList(String[] list) throws RemoteException {  
  75.             // TODO Auto-generated method stub  
  76.             /**  
  77.              * 取得客户端传入的值  
  78.              */  
  79.             if(list.length>0)  
  80.                 info=list[0];  
  81.         }  
  82.           
  83.     };  
  84. }  
3、开放一个标志,用于客户端访问
常用的做法,我们可以在AndroidManifest.xml中做如下定义:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <application  
  2.        android:allowBackup="true"  
  3.        android:icon="@drawable/ic_launcher"  
  4.        android:label="@string/app_name"  
  5.        android:theme="@style/AppTheme" >  
  6.        <service  
  7.            android:name="com.example.aidl_server_csdn.AIDLService"  
  8.            >  
  9.            <intent-filter>  
  10.             <action android:name="com.service.use"></action>  
  11.                </intent-filter>  
  12.            </service>  
  13.    </application>  
我们设定了一个过滤值:com.service.use,客户端可以通过这个来访问服务端。


至此,我们服务端的代码就写完了。当你运行该服务端在android系统上时,系统会安装一个service.apk并运行。

AIDL客户端(Client端)的实现

服务端已经实现好了,那客户端要如何调用呢?
按我们朴素的思想,应该就是获取服务端的实例,并用这个实例调用相应的方法了。AIDL也是这么想的。但AIDL的做法有点特别。
1、复制服务端的AIDL接口和Parcelable类等到服务端(习惯的做法,将AIDL的整个包都复制到客户端);
2、连接服务端;
3、获取服务端的接口实现的实例;
4、调用方法;
我们也按这步骤来实现我们的客户端。
1、复制整个AIDL包到客户端
这个你复制,黏贴即可。
2、连接服务端
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /**  
  2.      * 连接AIDL  
  3.      */  
  4.     public void Connect()  
  5.     {  
  6.         bindService(new Intent("com.service.use"), serviceConnection, Context.BIND_AUTO_CREATE);  
  7.     }  
  8.     /**  
  9.      * 连接类实现  
  10.      */  
  11.     ServiceConnection serviceConnection=new ServiceConnection() {  
  12.           
  13.         @Override  
  14.         public void onServiceDisconnected(ComponentName name) {  
  15.             // TODO Auto-generated method stub  
  16.             iBase=null;  
  17.             Toast.makeText(MainActivity.this, "连接断开", Toast.LENGTH_SHORT).show();  
  18.         }  
  19.           
  20.         @Override  
  21.         public void onServiceConnected(ComponentName name, IBinder service) {  
  22.             // TODO Auto-generated method stub  
  23.             iBase=IBase.Stub.asInterface(service);  
  24.             Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();  
  25.         }  
  26.     };  
  27.       
3、获取服务端的实例
其实,这个一般在连接服务端成功的时候,就已经做了,就如上面代码中的iBase=IBase.Stub.asInterface(service);
4、调用方法
我们在上一步骤中,已经获得了iBase实例,调用方法时,我们用以下方法:
 iBase.add(7, 8);
iBase.setaList(new String[]{"战国剑"});
等。
下面,贴出客户端调用的所有代码:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.example.aidl_csdn;  
  2.   
  3. import com.example.aidl.IBase;  
  4. import com.example.aidl.UserInfo;  
  5.   
  6. import android.os.Bundle;  
  7. import android.os.IBinder;  
  8. import android.os.RemoteException;  
  9. import android.view.View;  
  10. import android.view.View.OnClickListener;  
  11. import android.widget.Button;  
  12. import android.widget.Toast;  
  13. import android.R.integer;  
  14. import android.app.Activity;  
  15. import android.content.ComponentName;  
  16. import android.content.Context;  
  17. import android.content.Intent;  
  18. import android.content.ServiceConnection;  
  19.   
  20. public class MainActivity extends Activity implements OnClickListener{  
  21.   
  22.     IBase iBase;  
  23.     @Override  
  24.     protected void onCreate(Bundle savedInstanceState) {  
  25.         super.onCreate(savedInstanceState);  
  26.         setContentView(R.layout.activity_main);  
  27.         Button btn=(Button)findViewById(R.id.btn);  
  28.         btn.setOnClickListener(this);  
  29.         Button btn1=(Button)findViewById(R.id.btn1);  
  30.         btn1.setOnClickListener(this);  
  31.         Button btn2=(Button)findViewById(R.id.btn2);  
  32.         btn2.setOnClickListener(this);  
  33.         Button btn3=(Button)findViewById(R.id.btn3);  
  34.         btn3.setOnClickListener(this);  
  35.         Button btn4=(Button)findViewById(R.id.btn4);  
  36.         btn4.setOnClickListener(this);  
  37.         Button btn5=(Button)findViewById(R.id.btn5);  
  38.         btn5.setOnClickListener(this);  
  39.     }  
  40.   
  41.     /**  
  42.      * 连接AIDL  
  43.      */  
  44.     public void Connect()  
  45.     {  
  46.         bindService(new Intent("com.service.use"), serviceConnection, Context.BIND_AUTO_CREATE);  
  47.     }  
  48.     /**  
  49.      * 连接类实现  
  50.      */  
  51.     ServiceConnection serviceConnection=new ServiceConnection() {  
  52.           
  53.         @Override  
  54.         public void onServiceDisconnected(ComponentName name) {  
  55.             // TODO Auto-generated method stub  
  56.             iBase=null;  
  57.             Toast.makeText(MainActivity.this, "连接断开", Toast.LENGTH_SHORT).show();  
  58.         }  
  59.           
  60.         @Override  
  61.         public void onServiceConnected(ComponentName name, IBinder service) {  
  62.             // TODO Auto-generated method stub  
  63.             iBase=IBase.Stub.asInterface(service);  
  64.             Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();  
  65.         }  
  66.     };  
  67.       
  68.     /**  
  69.      * 基础类型相加  
  70.      * @return  
  71.      * @throws RemoteException  
  72.      */  
  73.     public  int  sum() {  
  74.         if(iBase!=null)  
  75.         {  
  76.             int result=0;  
  77.             try {  
  78.                 result = iBase.add(7, 8);  
  79.                 Toast.makeText(getApplicationContext(), "基础类型相加结果:"+result, Toast.LENGTH_SHORT).show();  
  80.             } catch (RemoteException e) {  
  81.                 // TODO Auto-generated catch block  
  82.                 e.printStackTrace();  
  83.             }  
  84.             return result;  
  85.         }  
  86.         return 0;  
  87.     }  
  88.     /**  
  89.      * in型传值到服务端  
  90.      */  
  91.     public void setaList()  
  92.     {  
  93.         if(iBase!=null)  
  94.         {  
  95.             try {  
  96.                 iBase.setaList(new String[]{"战国剑"});  
  97.                 Toast.makeText(getApplicationContext(), "传值'战国剑'到服务端", Toast.LENGTH_SHORT).show();  
  98.             } catch (RemoteException e) {  
  99.                 // TODO Auto-generated catch block  
  100.                 e.printStackTrace();  
  101.             }  
  102.         }  
  103.     }  
  104.     /**  
  105.      * out型取服务端返回值  
  106.      */  
  107.     public void getaList()  
  108.     {  
  109.         if(iBase!=null)  
  110.         {  
  111.             String[] list =new String[1];  
  112.             try {  
  113.                 iBase.getaList(list);  
  114.                 Toast.makeText(getApplicationContext(), "服务端返回内容:"+list[0], Toast.LENGTH_SHORT).show();  
  115.             } catch (RemoteException e) {  
  116.                 // TODO Auto-generated catch block  
  117.                 e.printStackTrace();  
  118.             }  
  119.         }  
  120.     }  
  121.     /**  
  122.      * Parcelable类的传入  
  123.      */  
  124.     public void ParcelableUse()  
  125.     {  
  126.         if(iBase==null)  
  127.             return;  
  128.         UserInfo userInfo=new UserInfo();  
  129.         userInfo.setName("战国剑");  
  130.         userInfo.setAdress("中国");  
  131.         userInfo.setAge(18);  
  132.          try {  
  133.              String resultString=iBase.getUserInfo(userInfo);  
  134.             Toast.makeText(getApplicationContext(), "服务端返回内容:"+resultString, Toast.LENGTH_SHORT).show();  
  135.         } catch (RemoteException e) {  
  136.             // TODO Auto-generated catch block  
  137.             e.printStackTrace();  
  138.         }  
  139.     }  
  140.       
  141.     /**  
  142.      * inout类型修饰的使用  
  143.      */  
  144.     public void inoutUse()  
  145.     {  
  146.         if(iBase==null)  
  147.             return;  
  148.         try {  
  149.             String[] inStrings={"inout中in的传入"};  
  150.             iBase.gettList(inStrings);  
  151.             Toast.makeText(getApplicationContext(), "inout服务端返回内容:"+inStrings[0], Toast.LENGTH_SHORT).show();  
  152.               
  153.         } catch (RemoteException e) {  
  154.             // TODO Auto-generated catch block  
  155.             e.printStackTrace();  
  156.         }  
  157.     }  
  158.       
  159.     @Override  
  160.     public void onClick(View v) {  
  161.         // TODO Auto-generated method stub  
  162.         switch (v.getId()) {  
  163.         case R.id.btn:  
  164.         Connect();  
  165.             break;  
  166.         case R.id.btn1:  
  167.             sum();  
  168.             break;  
  169.         case R.id.btn2:  
  170.             ParcelableUse();  
  171.             break;  
  172.         case R.id.btn3:  
  173.             setaList();  
  174.             break;  
  175.         case R.id.btn4:  
  176.             getaList();  
  177.             break;  
  178.         case R.id.btn5:  
  179.             inoutUse();  
  180.             break;  
  181.   
  182.         default:  
  183.             break;  
  184.         }  
  185.     }  
  186.   
  187. }  

至此,我们的客户端实现也完成了。运行后,你就可以看到你想要的效果。

注意信息

这是一个简单的AIDL实例,主要是为了说明AIDL中各种修饰符的使用和自定义类的传递。AIDL中,与我们常用方法不同的也就是这些东西,希望这个例子的分享有助于理解AIDL机制。

源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值