您的位置:首页 > 移动开发 > Android开发

Android实现进程间通信aidl的使用

2013-04-10 10:40 525 查看
这两天看了一下Android实现进程间通信binder的实现,在应用层的体现就是aidl的使用。这里也贴一下我参考的文献,

/article/4131702.html

现在总结一下这个用法:

其实很简单,主要就是以下的几个步骤:

1.第一步,定义aidl文件(可以参照IWifiManager.java的定义来实现,其实就是定义一个Interface,提供被调用的方法);

例如 (IMyService.aidl):

package com.demo;

import com.demo.Person;

interface IMyService {

void savePersonInfo(in Person person);//注意,这里的Person类不是基本数据类型哦,要进行处理的,见下文

List<Person> getAllPerson();

}

2.第二步,写一个service,实现stub类(也就是实现刚才的那些接口),return
stub类的对象(也就是binder);


创建一个类实现刚才那个aidl的接口:

public class RemoteService extends Service
{

private LinkedList<Person> personList = new LinkedList<Person>();

@Override

public IBinder onBind(Intent intent) { //activity

return mBinder;

}

private final IMyService.Stub
mBinder = new IMyService.Stub(){

@Override

public void savePersonInfo(Person
person) throws RemoteException {

if (person != null){

personList.add(person);

}

}

@Override

public List<Person> getAllPerson() throws RemoteException
{

return personList;

}

};

}

注:

这里会看到有一个名为IMyService.Stub类,查看aidl文件生成的Java文件源代码就能发现有这么一段代码:

/** Local-side IPC implementation stub class. */

public static abstract class Stub extends android.os.Binder implements com.demo.IMyService

原来Stub类就是继承于Binder类,也就是说RemoteService类和普通的Service类没什么不同,只是所返回的IBinder对象比较特别,是一个实现了AIDL接口的Binder。

3.第三步,在activity里面启动service。

通过IMyService.Stub.asInterface(service)来得到IMyService对象:

private IMyService mRemoteService;

private ServiceConnection mRemoteConnection = new ServiceConnection()
{

public void onServiceConnected(ComponentName
className, IBinder service) {

mRemoteService = IMyService.Stub.asInterface(service);

}

public void onServiceDisconnected(ComponentName
className) {

mRemoteService = null;

}

};

注:

在生成的IMyService.java里面会找到这样的代码:

/**

* Cast an IBinder object into an com.demo.IMyService interface,

* generating a proxy if needed.

*/

public static com.demo.IMyService
asInterface(android.os.IBinder obj) {...}

而service的绑定没有什么不同:

if (mIsRemoteBound) {

unbindService(mRemoteConnection);

}else{

bindService(new Intent("com.demo.IMyService"),

mRemoteConnection, Context.BIND_AUTO_CREATE);

}

mIsRemoteBound = !mIsRemoteBound;

通过IPC调用/传递数据

客户端绑定service后就能通过IPC来调用/传递数据了,直接调用service对象的接口方法:

addPersonButton.setOnClickListener(

new View.OnClickListener(){

private int index
= 0;

@Override

public void onClick(View
view) {

Person person = new Person();

index = index + 1;

person.setName("Person" + index);

person.setAge(20);

person.setTelNumber("123456");

try {

mRemoteService.savePersonInfo(person);

} catch (RemoteException e) {

e.printStackTrace();

}

}

});

listPersonButton.setOnClickListener(

new View.OnClickListener(){

@Override

public void onClick(View
view) {

List<Person> list = null;

try {

list = mRemoteService.getAllPerson();

} catch (RemoteException e) {

e.printStackTrace();

}

if (list != null){

StringBuilder text = new StringBuilder();

for(Person person : list){

text.append("\nPerson name:");

text.append(person.getName());

text.append("\n age :");

text.append(person.getAge());

text.append("\n tel number:");

text.append(person.getTelNumber());

}

inputPersonEdit.setText(text);

}else {

Toast.makeText(ServiceActivity.this, "get
data error",

Toast.LENGTH_SHORT).show();

}

}

});

另外关于第一步,附加的说一下。当aidl中的接口中的返回值或参数不是基本数据类型时,需要做如下的两步:
1.给一个aidle的实现:

package com.demo;

parcelable Person;

2.给一个序列化(实现java类)

public class Person implements Parcelable
{

private String name;

private String telNumber;

private int age;

public Person() {}

public Person(Parcel
pl){

name = pl.readString();

telNumber = pl.readString();

age = pl.readInt();

}

public String getName() {

return name;

}

public void setName(String
name) {

this.name = name;

}

public String getTelNumber() {

return telNumber;

}

public void setTelNumber(String
telNumber) {

this.telNumber = telNumber;

}

public int getAge()
{

return age;

}

public void setAge(int age)
{

this.age = age;

}

@Override

public int describeContents()
{

return 0;

}

@Override

public void writeToParcel(Parcel
dest, int flags) {

dest.writeString(name);

dest.writeString(telNumber);

dest.writeInt(age);

}

public static final Parcelable.Creator<Person>
CREATOR = new Parcelable.Creator<Person>() {

@Override

public Person createFromParcel(Parcel source) {

return new Person(source);

}

@Override

public Person[] newArray(int size)
{

return new Person[size];

}

};

}

Parcelable需要实现三个函数:
1) void
writeToParcel(Parcel dest, int flags) 将需要序列化存储的数据写入外部提供的Parcel对象dest。而看了网上的代码例子,个人猜测,读取Parcel数据的次序要和这里的write次序一致,否则可能会读错数据。具体情况我没试验过!

2) describeContents() 没搞懂有什么用,反正直接返回0也可以

3) static final Parcelable.Creator对象CREATOR 这个CREATOR命名是固定的,而它对应的接口有两个方法:

createFromParcel(Parcel source) 实现从source创建出JavaBean实例的功能

newArray(int size) 创建一个类型为T,长度为size的数组,仅一句话(return new T[size])即可。估计本方法是供外部类反序列化本类数组使用。

至此,就ok啦~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: