Android中的应用程序都会运行在自己的进程里,可是如何让不同进程之间通信和数据交换呢,Android提供了AIDL(
Android Interface definition language),它是一种Android内部进程通信接口额描述语言,用来实现跨进程通信(
interprocess communication,即IPC)。
(一)AIDL文件
Android需要使用AIDL来定义远程接口,它用来定义两个进程之间的通信接口,所以语法比较简单,AIDL接口与java接口相似,需要注意的是:
1.AIDL定义必须以.aidl 结尾。
2.AIDL中用到的数据类型,除了基本数据类型、String、List、Map、CharSequence之外,其他数据类型都需要导包,无论是否在同一个包中。
我们试着在当前包中创建一个aidl文件,命名:IPerson.aidl。
我们在aidl接口中定义两个方法
package com.lingyun.blog.aidl;
interface IPerson{
String getName();
int getAge();
interface IPerson{
String getName();
int getAge();
}
保存后,可以在gen目录下看到生成出了一个java接口文件,该接口中包含了一个
Stub内部类,该内部类实现了
Binder和IPerson两个接口,这个Stub类将会作为远程Service的回调类,可以作为onBind()方法的返回值。
(二)服务端-为客户端暴露接口
首先我们需要一个Service的实现类,同本地Service一样,通过onBind()方法实现Service通信,该方法返回的就是上一步所说的Stub内部类的子类的实例。
public class MyAIDLService extends Service {
private PersonBinder myPersonBinder = new PersonBinder();
//PersonBinder继承自Stub,而Stub实现了Binder接口,所以可以用于Service通信
public class PersonBinder extends Stub {
@Override
public String getName() throws RemoteException {
// TODO Auto-generated method stub
return "小明";
}
@Override
public int getAge() throws RemoteException {
// TODO Auto-generated method stub
return 22;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return myPersonBinder;
}
}
写完Service后,我们需要在AndroidMenifest.xml中配置
<service
android:name=".MyAIDLService">
<intent-filter >
<action android:name="com.lingyun.blog.action.MYAIDL_SERVICE"/>
</intent-filter>
</service>
(三)客户端-访问AIDL服务
AIDL接口定义了两个进程之间的通信接口,所以不仅服务端需要AIDL接口,客户端也需要AIDL接口,并且客户端和服务端需要对应,所以我们通过将服务端的AIDL文件复制到客户端中
定义一个布局文件,里面放一个按钮和一个文本框用来显示在上一个应用中的Service数据。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="onGetAIDLServiceClick"
android:text="获取远程Service数据" />
<TextView
android:id="@+id/textView_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
在Activity中实现数据回调对象的获取
public class MainActivity extends Activity {
private TextView tv_message;
private IPerson myPerson;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
myPerson = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
myPerson = IPerson.Stub.asInterface(service);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_message = (TextView)findViewById(R.id.textView_message);
Intent intent = new Intent();
intent.setAction("com.lingyun.blog.action.MYAIDL_SERVICE");
//绑定远程Service
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
public void onGetAIDLServiceClick(View v){
try {
tv_message.setText("姓名:"+myPerson.getName()+"年龄:"+myPerson.getAge());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unbindService(conn);
}
}
需要注意的是,在获取Service回调对象时,本地Service是直接获取onBinder()的返回值,而远程Service是返回对象的代理,所以需要类似 IPerson.Stub.asInterface(service)进行处理。 另外服务端和客户端的AIDL文件需要采用同样的包名,这样才能找到。