Android远程接口之AIDL——Parcelable、in、out、inout简例
2016-01-25 00:21
846 查看
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; } @Override public int describeContents() { // TODO Auto-generated method stub return 0; } @Override public void writeToParcel(Parcel dest, int flags) { // TODO Auto-generated method stub dest.writeString(name); dest.writeString(adress); dest.writeInt(age); } public static final Parcelable.Creator<UserInfo> CREATOR=new Creator<UserInfo>() { @Override public UserInfo createFromParcel(Parcel source) { // TODO Auto-generated method stub UserInfo userInfo=new UserInfo(); userInfo.setName(source.readString()); userInfo.setAdress(source.readString()); userInfo.setAge(source.readInt()); return userInfo; } @Override public UserInfo[] newArray(int size) { // TODO Auto-generated method stub return 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=""; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return stub; } private IBase.Stub stub=new IBase.Stub() { /** * 基本类型的使用示例 */ @Override public int add(int i, int j) throws RemoteException { // TODO Auto-generated method stub return i+j; } /** * Parcelable类userinfo的使用示例 */ @Override public String getUserInfo(UserInfo userinfo) throws RemoteException { // TODO Auto-generated method stub String resultString="name:"+userinfo.getName()+" "+"adress:"+userinfo.getAdress()+" "+"age:"+userinfo.getAge(); return resultString; } /** * out修饰类型的使用 * 表示服务端输入 */ @Override public void getaList(String[] list) throws RemoteException { // TODO Auto-generated method stub list[0]="服务端赋值信息:"+info; } /** * inout修饰类型的使用示例 */ @Override public void gettList(String[] list) throws RemoteException { // TODO Auto-generated method stub String totalString=""; /** * 从客户端取得的信息 */ String receviceFromClientString=""; for(int i=0;i<list.length;i++) { receviceFromClientString+=list[i]; } /** * 从服务端返回的信息 */ totalString+="从客户端收到的信息为:"+receviceFromClientString+" \n在此我们新增一段返回信息:good"; list[0]=totalString; } /** * in修饰类型的使用示例 */ @Override public void setaList(String[] list) throws RemoteException { // TODO Auto-generated method stub /** * 取得客户端传入的值 */ if(list.length>0) info=list[0]; } }; }
3、开放一个标志,用于客户端访问
常用的做法,我们可以在AndroidManifest.xml中做如下定义:<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <service android:name="com.example.aidl_server_csdn.AIDLService" > <intent-filter> <action android:name="com.service.use"></action> </intent-filter> </service> </application>我们设定了一个过滤值: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() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub iBase=null; Toast.makeText(MainActivity.this, "连接断开", Toast.LENGTH_SHORT).show(); } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub iBase=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;
@Override
protected 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() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub iBase=null; Toast.makeText(MainActivity.this, "连接断开", Toast.LENGTH_SHORT).show(); } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub iBase=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 block
e.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 block
e.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 block
e.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 block
e.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 block
e.printStackTrace();
}
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (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相关文章推荐
- PreparedStatement中in子句的处理
- 遭遇Reply from : TTL expired in transit.
- "TTL expired in transit" 具体解释第1/3页
- SQL SERVER中关于exists 和 in的简单分析
- SQL查询中in和exists的区别分析
- C#中out保留字用法实例分析
- 在MySQL中创建带有IN和OUT参数的存储过程的方法
- ref与out之间的区别深入解析
- IIS访问ASP页面时报错The requested resource is in use.的解决办法
- 一看就懂:图解C#中的值类型、引用类型、栈、堆、ref、out
- C#中out与ref的区别实例解析
- js中for in语句的用法讲解
- Some tips of wmi scripting in jscript (1)
- Linux的获利之路
- Ajax in action 英文版配书源码 下载
- Select data from an Excel sheet in MSSQL
- SQL实现递归及存储过程中In()参数传递解决方案详解
- Mysql子查询IN中使用LIMIT应用示例
- Oracle In和exists not in和not exists的比较分析
- 24. Swap Nodes in Pairs