AIDL (Android Interface Definition Language), Android接口定义语言,Android提供的IPC (进程间通信)的一种独特实现。
当你需要一个远程的service帮助你完成一些东西(最常见的音乐播放程序),同时也需要与它进行一些交互的时候 你就可以用Aidl实现(当然也可以用广播 不过效率比较低下 )
如何定义一个Aidl文件
必须在一个.aidl文件中使用java语法定义你的AIDL接口,然后在提供service的应用中和任何绑定到这个service的应用中的源代码中保存它。 注意几个问题 1.不能使用public等关键字去定义你的接口 抽象方法同理。2.你使用的任何一个自定义类 都需要导包 即使你的自定义类与aidl文件在同一个接口下 下面贴出来一个实例
首先建立一个新工程 工程完成以后 就建立最重要的aidl文件
aidl既然是接口定义语言 自然写法与接口类似 本人使用的是as 建造方法是右键你的moudle 选择AIDL 新建文件
文件创建后 会在src下生成一个与java同级的文件夹 你建立的aidl文件就在这个文件夹下
下面就可以编写你自己想定义的抽象方法 (注意不要使用public 关键字)
// IMyAidl.aidl
package com.example.main.aidltest;
// Declare any non-default types here with import statements
import com.example.main.aidltest.enity.Human;
interface IMyAidl {
String getMse();
void send(in Human human);
void sendMes(String str);
Human getHuman(String name,int age,String sex);
}
我定义了四个方法 基本涵盖了常用的几种形式 这里注意 aidl语言支持Java 的原生类型、String 和CharSequence、List 和 Map(里面的类型也必须是java的基本类型与String 和CharSequence)这些类型在使用的时候不需要导包就可以直接使用 但如果你需要使用自定义类型时候 一定要注意我以下说的话
自定义类可以使用 但是要注意 一定要继承Parcelable接口 如果不清楚什么是Parcelable的话
请看http://blog.csdn.net/u012702547/article/details/47151001 点击打开链接
实现接口以后 也不能使用 因为你编译以后会报 couldn't find import for class
你需要在你的aidl文件夹下建立一个与你的自定义类同名的aidl文件 并在在你的抽象方法中 引包(引的是你的自定义类名.aidl文件位置 不是自定义类的位置)
并且标注你文件是 in out 还是 inout属性 不明白的这三种关键字用法的 请看
http://www.open-open.com/lib/view/open1469494342021.html点击打开链接
我们实际操作下
首先是你自己的自定义类
public class Human implements Parcelable {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
private String name ;//名字
private int age;//年龄
private String sex;//性别
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.name);
dest.writeInt(this.age);
dest.writeString(this.sex);
}
public Human(String name,int age,String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
protected Human(Parcel in) {
this.name = in.readString();
this.age = in.readInt();
this.sex = in.readString();
}
public static final Parcelable.Creator<Human> CREATOR = new Parcelable.Creator<Human>() {
@Override
public Human createFromParcel(Parcel source) {
return new Human(source);
}
@Override
public Human[] newArray(int size) {
return new Human[size];
}
};
}
同时 在你的aidl文件夹下建立你的自定义类的aidl文件
// Human.aidl
package com.example.main.aidltest.enity;
parcelable Human;
最后在你需要的方法上 加入你的自定义类并加上关键字
void send(in Human human);
一个进程间通信的文件就建好了 下面就该建立一个远程服务了 不多说 直接上代码
public class YCService extends Service {
public YCService() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// return super.onStartCommand(intent, flags, startId);
return START_NOT_STICKY;//不重启
}
private final IMyAidl.Stub aidl=new IMyAidl.Stub() {
@Override
public String getMse() throws RemoteException {
return "远程service 向你问好";
}
@Override
public void send(Human human) throws RemoteException {LPLogUtil.debug(" 服务",human.getName()+human.getSex()+human.getAge());
}
@Override
public void sendMes(String str) throws RemoteException {
Toast.("服务",“activity说:”+str);
}
@Override
public Human getHuman(String name, int age, String sex) throws RemoteException {
Human human=new Human(name,age,sex);
return human;
}
};
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return aidl;
}
}
同时注意在你的manifests中注册
<service
android:name=".service.YCService"
android:enabled="true"
android:exported="true"
android:launchMode="singleTop"
android:process=":remote">
</service>
Android SDk工具基于你的.aidl文件使用java语言生成一个接口 这个接口有一个内部抽象类,叫做Stub,它是继承Binder并且实现你AIDL接口的 你必须继承这个Stub类并且实现这些方法 实现service并且覆盖onBind()方法返回你的Stub实现类。 当你编译你的应用时,Android SDK工具生成一个.java接口文件用你的.aidl文件命名生成的接口包含一个名字为Stub的子类,这是一个它父类的抽象实现,并且声明了.aidl中所有的方法。 Stub也定义了一些辅助的方法,最显著的就是asInterface(),它是用来接收一个IBinder(通常IBinder传递给客户端的onServiceConnected()回调方法)并且返回一个Stub接口的实例 。一旦你为service实现了接口,你需要把它暴露给客户端,这样他们才能绑定到上面 为了给你的service暴露接口,继承Service并且实现onBind()方法返回一个你实现生成的Stub类。
这样一个远程服务就做好了 现在做本地处理
一个最简单的activity 与四个按钮 这里就不粘上xml文件了
public class MainActivity extends AppCompatActivity {
private Activity activity;
private IMyAidl myAidl;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAidl = IMyAidl.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
myAidl = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
init();
}
private void init() {
Button startbind = (Button) findViewById(R.id.button);
Button getmse = (Button) findViewById(R.id.button2);
Button getHuman = (Button) findViewById(R.id.button3);
Button interactive = (Button) findViewById(R.id.button4);
startbind.setOnClickListener(listener);
getmse.setOnClickListener(listener);
getHuman.setOnClickListener(listener);
interactive.setOnClickListener(listener);
}
Human human = new Human("张三", 12, "男");
private final View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
Intent intent = new Intent(activity, YCService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
break;
case R.id.button2:
try {
if (myAidl != null) {
myAidl.sendMes("给远程大佬递茶");
myAidl.send(human);
} else {
Toast.makeText(activity, "服务未绑定", Toast.LENGTH_SHORT).show();
}
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.button3:
try {
if (myAidl != null) {
Toast.makeText(activity, myAidl.getMse(), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(activity, "服务未绑定", Toast.LENGTH_SHORT).show();
}
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case R.id.button4:
try {
if (myAidl != null) {
Human human = myAidl.getHuman("李雪", 11, "女");
Toast.makeText(activity, human.getName() + human.getAge() + human.getSex(), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(activity, "服务未绑定", Toast.LENGTH_SHORT).show();
}
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
};
}
ServiceConnection的作用就是将远程服务转化成一个你能直接使用的对象 注意要与远程服务绑定 不然就是空哦
ok都完事了 我们运行一下
远程端