编写ADIL文件时有以下注意事项:
1.接口名词需要与aidl文件名相同
2.接口和方法前面不要加访问权限修饰符:public ,private,protected等,也不能用static final!
3.AIDL默认支持的类型包括Java基本类型,String,List,Map,CharSequence,除此之外的其他类型都需要import
声明,对于使用自定义类型作为参数或者返回值,自定义类型需要实现Parcelable接口,后面会详细讲解。
4.自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。
IPerson.aidl文件内容如下:
package com.makk.aidlserver;
interface IPerson{
void setValue(String name);
String getValue();
}
|
package com.makk.aidlserver;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
private IPerson.Stub person = new Person();
@Override
public IBinder onBind(Intent intent) {
return person;
}
}
|
<service android:name="com.makk.aidlserver.MyService" >
<intent-filter>
<action android:name="com.makk.aidlserver.MyService" />
</intent-filter>
</service>
|
public void onClick(View view) {
switch (view.getId()) {
case R.id.button1:
Intent i = new Intent(this, MyService.class);
bindService(i, conn, Service.BIND_AUTO_CREATE);
break;
case R.id.button2:
unbindService(conn);
break;
default:
break;
}
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iPerson = IPerson.Stub.asInterface(service);
if (iPerson != null) {
try {
iPerson.setValue("makk is exist");
Toast.makeText(MainActivity.this, "赋值成功", Toast.LENGTH_SHORT)
.show();
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "赋值失败", Toast.LENGTH_SHORT)
.show();
}
}
}
};
}
|
调用bindService绑定远程Service
bindService(service, conn, BIND_AUTO_CREATE);
ps:第三个参数是设置如果服务没有启动的话,自动创建
和本地Service不同,绑定远程Service的ServiceConnection并不能直接获取Service的onBind( )方法
返回的IBinder对象,只能返回onBind( )方法所返回的代理对象,需要做如下处理:
iPerson = IPerson.Stub.asInterface(service);
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction("com.makk.aidlserver.MyService");
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
person = IPerson.Stub.asInterface(service);
if (person != null) {
try {
String value = person.getValue();
Toast.makeText(MainActivity.this, "获取成功:" + value,
Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "获取失败!!!",
Toast.LENGTH_SHORT).show();
}
}
}
};
}
|
1.)先要了解的是Parcelable接口,对于自定义类型,Android规定调用远程Service的参数与返回值都必须实现
Parcelable接口,该接口告诉Android运行时在封送(marshalling)和解封送(unmarshalling)过程中如何序列化。
与反序列化对象,这个时候你或许会有疑惑,为什么不直接用Java提供的Serializable接口呢?这是因为Android
团队觉得Java序列化太慢,难以满足Android的进程间的通信需求,所以他们构建了Parcelable方案!
---->也就是自定义的对象要实现Parcelable接口!实现接口要实现下述方法
实现Paecelable接口意味着要实现writeToParcel和readFromPacel方法;
写入方法将对象写入到包裹(parcel)中,而读取方法则从包裹中读取对象,请注意,写入属性顺序需与读取顺序相同
需要在该类中实现android.os.Parcelable.Creator<T>接口
该接口里面的两个方法:
createFromParcel(Parcel source)
|
实现从source创建出JavaBean实例的功能 |
newArray(int size):
|
创建一个类型为T,长度为size的数组,只有一个简单的return new T[size]; (这里的T是Person类) |
describeContents():这个我也不知道是拿来干嘛的,直接返回0即可!不用理他
2.)非原始类型中,除了String和CharSequence以外,其余均需要一个方向指示符。方向指示符包括
in、out、和inout。in表示由客户端设置,out表示由服务端设置,inout表示客户端和服务端都设置了该值。
package com.makk.aidlserver;
import android.os.Parcel;
import android.os.Parcelable;
public class Worker implements Parcelable {
private int id;
private String name;
public Worker() {
}
public Worker(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 实现Parcelable必须实现的方法,不知道拿来干嘛的,直接返回0就行了
@Override
public int describeContents() {
return 0;
}
// 写入数据到Parcel中的方法
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
// 必须提供一个名为CREATOR的static final属性 该属性需要实现
// android.os.Parcelable.Creator<T>接口
public static final Parcelable.Creator<Worker> CREATOR = new Creator<Worker>() {
@Override
public Worker[] newArray(int size) {
return new Worker[size];
}
@Override
public Worker createFromParcel(Parcel source) {
return new Worker(source.readInt(), source.readString());
}
};
// 因为我们集合取出元素的时候是根据Person对象来取得,所以比较麻烦,
// 需要我们重写hashCode()和equals()方法
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Worker other = (Worker) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
|
package com.makk.aidlserver;
import android.os.Parcel;
import android.os.Parcelable;
public class Salary implements Parcelable {
private String type;
private int salary;
public Salary() {
}
public Salary(String type, int salary) {
super();
this.type = type;
this.salary = salary;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(type);
dest.writeInt(salary);
}
public static final Parcelable.Creator<Salary> CREATOR = new Creator<Salary>() {
@Override
public Salary[] newArray(int size) {
return new Salary[size];
}
@Override
public Salary createFromParcel(Parcel source) {
return new Salary(source.readString(), source.readInt());
}
};
public String toString() {
return "工作:" + type + " 薪水" + salary;
};
}
|
package com.makk.aidlserver;
import com.makk.aidlserver.Worker;
import com.makk.aidlserver.Salary;
interface ISalary {
//定义一个Person对象作为传入参数
//接口中定义方法时,需要制定新参的传递模式,这里是传入,所以前面有一个in
Salary getMsg(in Worker owner);
}
|
package com.makk.aidlserver;
import java.util.HashMap;
import java.util.Map;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class SalaryService extends Service {
ISalary.Stub salary = new ISalary.Stub() {
@Override
public Salary getMsg(Worker owner) throws RemoteException {
Map<Worker, Salary> ss = new HashMap<Worker, Salary>();
// 初始化Map集合,这里在静态代码块中进行初始化,当然你可也以在构造方法中完成初始化
ss.put(new Worker(1, "Jay"), new Salary("码农", 2000));
ss.put(new Worker(2, "GEM"), new Salary("歌手", 20000));
ss.put(new Worker(3, "XM"), new Salary("学生", 20));
ss.put(new Worker(4, "MrWang"), new Salary("老师", 2000));
return ss.get(owner);
}
};
@Override
public IBinder onBind(Intent intent) {
return salary;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
|
<service android:name="com.makk.aidlserver.SalaryService" >
<intent-filter>
<action android:name="com.makk.aidlserver.SalaryService" />
</intent-filter>
</service>
|
Intent intent = new Intent(this, SalaryService.class);
bindService(intent, connSalary, Service.BIND_AUTO_CREATE);
|
intent.setAction("com.makk.aidlserver.MyService");
bindService(intent, conn, Service.BIND_AUTO_CREATE);
|
ServiceConnection connSalary = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
salary = ISalary.Stub.asInterface(service);
if (salary!=null) {
try {
Salary s = salary.getMsg(new Worker(1, "Jay"));
Toast.makeText(MainActivity.this, "获取成功:" + s.getType()+"salary:"+s.getSalary(),
Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(MainActivity.this, "获取失败!!!",
Toast.LENGTH_SHORT).show();
}
}
}
};
|