上一篇我们最后说到aidl,假定读到这篇的观众老爷们已经知道aidl是什么鬼了
不知道的自己查阅下资料,就会知道最基本的模型如下
在进程A中实现一个AIDL接口文件,进程B中也引用这个接口文件
// ITestService.aidl
package me.lzq.test;
// Declare any non-default types here with import statements
interface ITestService {
int sum(int a,int b);
}
该函数实现一个简单的加法功能
进程B中有一个服务叫做TestService,当A中的TestActivity启动TestService时,不使用startService,而是bindService
并且注册一个ServiceConnect对象,用来监听服务连接状况
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent service = new Intent(this, TestService.class);
bindService(service, conn, Service.BIND_AUTO_CREATE);
}
private ITestService binder;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = ITestService.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
在TestService中,实现ITestService中的sum方法,并在onBind中返回该接口对象
public class TestService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private ITestService.Stub binder = new ITestService.Stub(){
@Override
public int sum(int a, int b) throws RemoteException {
return a+b;
}
};
}
好了,以上就是最基本的aidl模型,已经熟悉的观众老爷们就当是一次复习吧
接下来才是我们本片文章的整体,数据传递部分
正如上面函数所示,我们传递的是基本数据类型int,那么如果我们要传递一个自定义类怎么办?
好吧,其实也是上文提到的Parcelable接口,不过有一点不同的是,我们需要在aidl中也声明这个类,如下
// A.aidl
package me.lzq.test;
// Declare any non-default types here with import statements
parcelable A;
注意这个aidl必须和java中的类A在一个package中,并且是同名
然后修改之前的ITestService.aidl,添加一个函数
interface ITestService {
int sum(int a,int b);
A modify(in A a);
}
输入一个类A的对象,并且返回一个类A,这样一来我们自定义的类也可以通过AIDL传递了
但是好像有些不完美的地方,是忘了什么吧?
对,为什么aidl中modify方法需要有一个in的关键字申明呢?在aidl中,自定义类有三种使用方式
in:顾名思义是输入,需要在客户端设置
out:输入,需要在服务器端设置
inout:两端均可设置
如果要使得你传入的自定义类可修改(相当于我们java中的对象引用),直接在类A中实现readFromParcel方法即可,完整的类A文件如下
public class A implements Parcelable {
int a;
long b;
String c;
public A(int a, long b, String c) {
this.a = a;
this.b = b;
this.c = c;
}
public A(Parcel source) {
a = source.readInt();
b = source.readLong();
c = source.readString();
}
@Override
public int describeContents() {
return 0;
}
public void readFromParcel(Parcel source) {
a = source.readInt();
b = source.readLong();
c = source.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(a);
dest.writeLong(b);
dest.writeString(c);
}
public final static Creator<A> CREATOR = new Creator<A>() {
@Override
public A createFromParcel(Parcel source) {
return new A(source);
}
@Override
public A[] newArray(int size) {
return new A[0];
}
};
}
这样一来,我们的自定义类就可以像之前在java中那样自由使用了
这样看来,似乎我们问题就都解决,但是还是有不完美的地方啊
因为我们每次使用一个自定义类就得去声明一个对应类型的aidl文件
这和我们实际开发不一样不一样啊!!!我们经常会对A进行继承
当在java中,我们可以通过多态来在一个函数中解决问题,可是aidl不是java啊!难道每次要传递一个继承的类,就需要声明一个aidl文件,并且在ITestService中声明一个新函数么?那么这也太不友好了,这不符合oo思想,对设计模式也会有极大的破坏
ok,问题还是好解决的,下一篇文章就会说明,如何使一个aidl传递的类,可以继承!