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,内容为:
package com.example.aidl;import com.example.aidl.UserInfo;//注意引用interface IBase{     int    add(int i,int j);     String getUserInfo(in UserInfo userinfo);     void   getaList(out String[] list);       void   setaList(in String[] list);     void   gettList(inout String[] list);}
上方的接口中的方法,我们演示了各种修饰符以及Parcelable。 这里有个需要注意的地方,我们在文件头中有import一个类,这个是必要的,虽然UserInfo类和我们定义的接口是在同一个包下。 Parcelable的使用,我们首先要实现这个UserInfo的Parcelable接口实现,然后引用它,如下:
package com.example.aidl;import android.os.Parcel;import android.os.Parcelable;public class UserInfo implements Parcelable{private String name;private String adress;private int  age;/** * @return the name */public String getName() {return name;}/** * @param name the name to set */public void setName(String name) {this.name = name;}/** * @return the adress */public String getAdress() {return adress;}/** * @param adress the adress to set */public void setAdress(String adress) {this.adress = adress;}/** * @return the age */public int getAge() {return age;}/** * @param age the age to set */public void setAge(int age) {this.age = age;}@Overridepublic int describeContents() {// TODO Auto-generated method stubreturn 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {// TODO Auto-generated method stubdest.writeString(name);dest.writeString(adress);dest.writeInt(age);}   public static final Parcelable.Creator CREATOR=new Creator() {@Overridepublic UserInfo createFromParcel(Parcel source) {// TODO Auto-generated method stubUserInfo userInfo=new UserInfo();userInfo.setName(source.readString());userInfo.setAdress(source.readString());userInfo.setAge(source.readInt());return userInfo;}@Overridepublic UserInfo[] newArray(int size) {// TODO Auto-generated method stubreturn new UserInfo[size];}};}
声明这个自定义类: 在同一个包下,创建一个UserInfo.aidl文件,内容如下:
package com.example.aidl;parcelable UserInfo;

综合以上,在使用自定义类时,需要有几个步骤: (1)实现Parcelable接口,具体过程可参考: http://blog.csdn.net/yangzhaomuma/article/details/50452651;
(2)在同一包名下,创建类同名的AIDL文件; (3)在使用该类时,需要在文件头引用(import)。

2、实现接口方法:

新建一个java文件,我们暂命名为:AIDLService.java,该文件是实现AIDL的接口。内容如下:
package com.example.aidl_server_csdn;import com.example.aidl.IBase;import com.example.aidl.UserInfo;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;public class AIDLService extends Service{String info="";@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn stub;}private IBase.Stub stub=new IBase.Stub() {/** * 基本类型的使用示例 */@Overridepublic int add(int i, int j) throws RemoteException {// TODO Auto-generated method stubreturn i+j;}/** * Parcelable类userinfo的使用示例 */@Overridepublic String getUserInfo(UserInfo userinfo) throws RemoteException {// TODO Auto-generated method stubString resultString="name:"+userinfo.getName()+" "+"adress:"+userinfo.getAdress()+" "+"age:"+userinfo.getAge();return resultString;}/** * out修饰类型的使用 * 表示服务端输入 */@Overridepublic void getaList(String[] list) throws RemoteException {// TODO Auto-generated method stublist[0]="服务端赋值信息:"+info;}/** * inout修饰类型的使用示例 */@Overridepublic void gettList(String[] list) throws RemoteException {// TODO Auto-generated method stubString totalString="";/** * 从客户端取得的信息 */String receviceFromClientString="";for(int i=0;i0)info=list[0];}};}

3、开放一个标志,用于客户端访问

常用的做法,我们可以在AndroidManifest.xml中做如下定义:
                                                                  
我们设定了一个过滤值:com.service.use,客户端可以通过这个来访问服务端。


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

AIDL客户端(Client端)的实现

服务端已经实现好了,那客户端要如何调用呢? 按我们朴素的思想,应该就是获取服务端的实例,并用这个实例调用相应的方法了。AIDL也是这么想的。但AIDL的做法有点特别。 1、复制服务端的AIDL接口和Parcelable类等到服务端(习惯的做法,将AIDL的整个包都复制到客户端); 2、连接服务端; 3、获取服务端的接口实现的实例; 4、调用方法; 我们也按这步骤来实现我们的客户端。

1、复制整个AIDL包到客户端

这个你复制,黏贴即可。

2、连接服务端

/** * 连接AIDL */public void Connect(){bindService(new Intent("com.service.use"), serviceConnection, Context.BIND_AUTO_CREATE);}/** * 连接类实现 */ServiceConnection serviceConnection=new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubiBase=null;Toast.makeText(MainActivity.this, "连接断开", Toast.LENGTH_SHORT).show();}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubiBase=IBase.Stub.asInterface(service);Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();}};

3、获取服务端的实例

其实,这个一般在连接服务端成功的时候,就已经做了,就如上面代码中的iBase=IBase.Stub.asInterface(service);

4、调用方法

我们在上一步骤中,已经获得了iBase实例,调用方法时,我们用以下方法:  iBase.add(7, 8);
iBase.setaList(new String[]{"战国剑"});
等。 下面,贴出客户端调用的所有代码:
package com.example.aidl_csdn;import com.example.aidl.IBase;import com.example.aidl.UserInfo;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;import android.R.integer;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;public class MainActivity extends Activity implements OnClickListener{IBase iBase;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btn=(Button)findViewById(R.id.btn);btn.setOnClickListener(this);Button btn1=(Button)findViewById(R.id.btn1);btn1.setOnClickListener(this);Button btn2=(Button)findViewById(R.id.btn2);btn2.setOnClickListener(this);Button btn3=(Button)findViewById(R.id.btn3);btn3.setOnClickListener(this);Button btn4=(Button)findViewById(R.id.btn4);btn4.setOnClickListener(this);Button btn5=(Button)findViewById(R.id.btn5);btn5.setOnClickListener(this);}/** * 连接AIDL */public void Connect(){bindService(new Intent("com.service.use"), serviceConnection, Context.BIND_AUTO_CREATE);}/** * 连接类实现 */ServiceConnection serviceConnection=new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {// TODO Auto-generated method stubiBase=null;Toast.makeText(MainActivity.this, "连接断开", Toast.LENGTH_SHORT).show();}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// TODO Auto-generated method stubiBase=IBase.Stub.asInterface(service);Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();}};/** * 基础类型相加 * @return * @throws RemoteException */public  int  sum() {if(iBase!=null){int result=0;try {result = iBase.add(7, 8);Toast.makeText(getApplicationContext(), "基础类型相加结果:"+result, Toast.LENGTH_SHORT).show();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}return result;}return 0;}/** * in型传值到服务端 */public void setaList(){if(iBase!=null){try {iBase.setaList(new String[]{"战国剑"});Toast.makeText(getApplicationContext(), "传值'战国剑'到服务端", Toast.LENGTH_SHORT).show();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}/** * out型取服务端返回值 */public void getaList(){if(iBase!=null){String[] list =new String[1];try {iBase.getaList(list);Toast.makeText(getApplicationContext(), "服务端返回内容:"+list[0], Toast.LENGTH_SHORT).show();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}/** * Parcelable类的传入 */public void ParcelableUse(){if(iBase==null)return;UserInfo userInfo=new UserInfo();userInfo.setName("战国剑");userInfo.setAdress("中国");userInfo.setAge(18); try { String resultString=iBase.getUserInfo(userInfo);Toast.makeText(getApplicationContext(), "服务端返回内容:"+resultString, Toast.LENGTH_SHORT).show();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/** * inout类型修饰的使用 */public void inoutUse(){if(iBase==null)return;try {String[] inStrings={"inout中in的传入"};iBase.gettList(inStrings);Toast.makeText(getApplicationContext(), "inout服务端返回内容:"+inStrings[0], Toast.LENGTH_SHORT).show();} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublic void onClick(View v) {// TODO Auto-generated method stubswitch (v.getId()) {case R.id.btn:Connect();break;case R.id.btn1:sum();break;case R.id.btn2:ParcelableUse();break;case R.id.btn3:setaList();break;case R.id.btn4:getaList();break;case R.id.btn5:inoutUse();break;default:break;}}}

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

注意信息

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

源码

源码地址: http://download.csdn.net/detail/yangzhaomuma/9416663

更多相关文章

  1. Nginx系列教程(二)| 一文带你读懂Nginx的正向与反向代理
  2. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  3. android移动支付——支付宝支付
  4. 简单新闻客户端APP设计
  5. 基于Socket的Android聊天室
  6. android 的AIDL学习
  7. Android(安卓)蓝牙(概述)
  8. 7、与iOS、Android的交互 高级篇
  9. Android的Socket 通信

随机推荐

  1. Java中累计时间的计算(以小时为最终结果)
  2. Java读取Unicode文件(UTF-8等)时碰到的BOM
  3. java类与对象,用程序解释
  4. idea配置完tomcat启动键为什么还是灰的
  5. java数组的拷贝四种方法:for、clone、Syst
  6. “java.exe”已退出,代码为 1。
  7. 经典算法问题的java实现
  8. java高并发测试实例(精确到几百纳秒)
  9. java中的大事件
  10. 给定一个整数数组,找出两个下标,要求后面下