Android兑现进程间通信aidl的使用
Android实现进程间通信aidl的使用
注:
2) describeContents() 没搞懂有什么用,反正直接返回0也可以
3) static final Parcelable.Creator对象CREATOR 这个CREATOR命名是固定的,而它对应的接口有两个方法:
createFromParcel(Parcel source) 实现从source创建出JavaBean实例的功能
newArray(int size) 创建一个类型为T,长度为size的数组,仅一句话(return new T[size])即可。估计本方法是供外部类反序列化本类数组使用。
这两天看了一下Android实现进程间通信binder的实现,在应用层的体现就是aidl的使用。这里也贴一下我参考的文献,
http://android.blog.51cto.com/268543/537684
现在总结一下这个用法:
其实很简单,主要就是以下的几个步骤:
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();
}
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;
}
};
}
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
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;
}
};
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) {...}
* 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;
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();
}
}
});
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;
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];
}
};
}
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啦~