Android中的数据传输、方法调用等,常见的是集中在应用程序内的Activity之间,如Activity-A传递到Activity-B。
这样的数据传输、方法等都是在一个应用程序间调用,也就是在一个进程内。那如果我们要在不同的进程间传递数据,我们要怎么做呢?不在同一个进程间,它们是无法共用内存的,Android为了实现进程间的数据共享,提供了AIDL机制(安卓远程接口定义语言)——(AIDL: Android Interface definition language)。
AIDL的原理以及原理分析,可参考网上其他的解释。
下文将主要介绍AIDL的各种修饰符(in、out、inout)以及类序列化Parcelable的使用示例(网上原理解释很多,但对out、inout的示例很少见到)。
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:这个可以叫输入输出参数,客户端可输入、服务端也可输入。客户端输入了参数到服务端后,服务端也可对该参数进行修改等,最后在客户端上得到的是服务端输出的参数。
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。
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 CREATOR=new Creator() {
@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];
}
};
}
声明这个自定义类:
package com.example.aidl;
parcelable UserInfo;
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;i0)
info=list[0];
}
};
}
我们设定了一个过滤值:com.service.use,客户端可以通过这个来访问服务端。
/**
* 连接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();
}
};
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;
}
}
}