AIDL定义:可以定义客户端跟服务使用进程间通信(IPC)进行相互通信时都认可的编程接口。
AIDL用途:将其对象分解成操作系统能够识别的原语,并将对象编组成跨越边界的对象。
AIDL使用环境:允许不同应用的客户端用IPC方式访问服务,并且想要在服务中处理多线程时。
不需要AIDL的情况:[1].使用Binder:不需要执行跨越不同应用的并发IPC,就应该通过实现一个Binder创建接口;[2].使用Messenger类:想执行IPC,但根本不需要处理多线程,则使用Message类来实现接口。
我们把aidl通讯分两部分讲解,第一部分是activity访问其它应用的service,第二部分是service访问activity。之所以这样讲解是因为我在刚接触aidl的时候比较容易混淆。
第一部分:下面的例子是AIDLClientDemo应用通过aidl访问AIDLServiceDemo应用中的service。
一、先建立mylibrary module
1、在AIDLDemo工程下创建一个Library module,然后在src/main下创建aidl文件夹(跟java文件夹同一层级);
2、在aidl文件夹下创建IConnectClientInterface.aidl文件,代码如下:
interface IConnectClientInterface {
int getServiceValue();
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
建立完这个文件后运行下gradle系统会自动在build/generated/source/aidl/debug/包名/这个目录下生成IConnectClientInterface.java文件。
对于每一个.aidl文件系统都会生成一个基于.aidl文件的IBinder接口(这里是IConnectClientInterface.java)。每个服务根据自己的情况实现IBinder接口。客户端应用绑定到该服务,并调用IBinder中的方法来执行IPC。
二、第二步建立aidlservicedemo module,并且引入library module。
1、创建一个Service文件MyService.java,代码如下:
public class MyService extends Service {
int value=1234;
public MyService() {
}
private final IConnectClientInterface.Stub iConnectClientBind=new IConnectClientInterface.Stub() {
@Override
public int getServiceValue() throws RemoteException {
return value;
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
};
@Override
public IBinder onBind(Intent intent) {
return iConnectClientBind;
}
}
IConnectClientInterface.Stub是其父接口的抽象实现,用于声明.aidl文件中的所有方法。iConnectClientBind是Stub类的一个实例(一个Binder),用于定义服务的RPC(远程进程请求)接口。
扩展Service并实现onBind(),返回一个IBinder实例(这里指iConnectClientBind)。
2、在AndroidManifest.xml中配置如下:
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="zfeng.com.aidldemo.MyService"></action>
</intent-filter>
</service>
android:exported=“true”表示外部应用可以访问这个Service,这里的action起到过滤的作用。
三、建立aidlclientdemo module,并且引入library module。
1、创建一个Activity文件BindingActivity.java。
public class BindingOtherServiceActivity extends AppCompatActivity {
Button btn;
TextView textView;
private IConnectClientInterface mService;
private ServiceConnection mServiceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService=IConnectClientInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService=null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_binding_other_service);
textView=(TextView)findViewById(R.id.showAidl);
btn=(Button)findViewById(R.id.bindServicebtn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent("zfeng.com.aidldemo.MyService");
intent.setClassName("zfeng.com.aidlservicedemo","zfeng.com.aidlservicedemo.MyService");
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
}
});
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mService!=null){
textView.post(new Runnable() {
@Override
public void run() {
try{
textView.setText(mService.getServiceValue()+"value");
}catch (Exception e){
e.printStackTrace();
}
}
});
}else{
Toast.makeText(BindingOtherService.this, "Service is not available yet!", Toast.LENGTH_SHORT).show();
}
}
});
}
}
现在,当BindingOtherServiceActivity调用bindService()连接MyService时,Activity的onServiceConnected()回调会接收MyService的onBind()方法返回的mBinder实例。
当客户端在onServiceConnected()回调中收到IBinder时,它必须调用YourServiceInterface.Stub.asInterface(service)以将返回的参数转换成YourServiceInterface类型。
四、运行AIDLClientDemo和AIDLServiceDemo测试。
第二部分:service主动获取另一个app中activity的值。
这个问题刚开始的时候很纠结,因为官方文档的例子中有一个CallBack的aidl,所以我一直在纠结是不是Service调用CallBack来获取Activity的信息。但是我在从Activity往Service中传递aidl对象(IConnectCallbackInterface)时,传入的都是空值,最后发现了问题所在,我们应该实例化Stub。
代码步骤如下(文件所在位置基本与第一部分一致):
1、创建IConnectCallbackInterface.aidl,并且修改IConnectClientInterface.aidl.aidl
interface IConnectCallbackInterface {
void putValue(int activityValue);
}
interface IConnectClientInterface {
int getServiceValue();
void registerConnectCallback(IConnectCallbackInterface cb);
}
2
、在
BindingOtherServiceActivity.java
中实例化
aidl
,并且在IConnectClientInterface.aidl中注册。
private IConnectCallbackInterface.Stub callbackInterface=new IConnectCallbackInterface.Stub() {
@Override
public void putValue(final int activityValue) throws RemoteException {
textView.post(new Runnable() {
@Override
public void run() {
textView.setText(activityValue+" from service");
}
});
}
@Override
public IBinder asBinder() {
return callbackInterface;
}
};
mService.registerConnectCallback(callbackInterface);
3、在MyService.java中操作
private final IConnectClientInterface.Stub iConnectClientBind=new IConnectClientInterface.Stub() {
@Override
public int getServiceValue() throws RemoteException {
return value;
}
@Override
public void setServiceValue(int activityValue)throws RemoteException{
value=activityValue;
}
@Override
public void registerConnectCallback(IConnectCallbackInterface cb){
callbackInterface=cb;
try{
callbackInterface.putValue(4567);
}catch (Exception e){
e.printStackTrace();
}
}
};
4
、大功告成。
参考资料:
https://developer.android.google.cn/guide/components/aidl.html?hl=zh-cn