Android中AIDL的使用
本次以一个简单的小例子说明AIDL在Android的使用,客户端通过AIDL调用服务端提供的服务获得一个字符串“I’m service !”,并在客户端显示,以此小例子简单说明AIDL的使用方法。
1、AIDL服务端的建立
AIDL可用于两个不同进程中的通信(内部其实是Binder之间的通信),首先看一下使用AIDL的Service如何建立:
1.1 建立AIDL文件
、
建立该文件后,然后添加一个方法,IMyService的内容如下:
@IMyService.aidl
// IMyService.aidl
package com.example.administrator.myservice;
// Declare any non-default types here with import statements
interface IMyService {
String sayHello();
}
1.2服务端实现ADIL接口中的sayHello方法
@MyService.java
package com.example.administrator.myservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class MyService extends Service {
private static final String FROME_SERVICE = "I'm service !";
private class MyServiceImpl extends IMyService.Stub{
@Override
public String sayHello() throws RemoteException {
return FROME_SERVICE;
}
}
IBinder mIBinder = new MyServiceImpl();
@Override
public IBinder onBind(Intent intent) {
return mIBinder;
}
}
在这里可以看见MyService的内部类MyServiceImpl继承了IMyService.Stub这个抽象类,并实现了sayHello这个方法。在这里需要知道在建立IMyService.aidl这个文件之后,在经过手动编译之后系统会自动生成IMyService.java这个文件,这里暂时先不介绍这个自动生成的文件,这个文件留到最后讨论,目前先完成我们的小例子,先看看这个AIDL到底是如何使用的,更深层次的暂时不讨论,先会用了,再进行下一步。
服务端的代码就这么简单,接下来看看客户端如何调用服务端。
2、AIDL客户端的调用实现
2.1 客户端配置AIDL
首先还是要在客户端先建立一个工程,建立之后将服务端的project目录下app目录下src目录下的aidl文件夹(包含该目录下的所有文件)拷贝到对应的客户端目录下,拷贝完成之后手动编译客户端代码即可。
2.2 客户端准备调用服务端
@MainActivity
package com.example.administrator.myclient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.example.administrator.myservice.IMyService;
public class MainActivity extends AppCompatActivity {
private TextView mTest = null;
private IMyService mService = null;
private String PACK_NAME = "com.example.administrator.myservice";
private String ACTION = "com.example.administrator.myservice.IMyService";
//ServiceConnection 对象用于连接远程服务
private ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if(null != service){
//获得AIDL服务端的对象,调用其他进程中的方法
mService = IMyService.Stub.asInterface(service);
try {
//sayHello方法已在服务端实现,远程调用服务端方法
mTest.setText(mService.sayHello());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
callAidlService();
}
//绑定服务,绑定成功会调用ServiceConnection的onServiceConnected,
//从而客户端得到服务端的IMyService。
//此例子中得到的实际上是IMyService的子类MyServiceImpl对象。
private void callAidlService() {
Intent intent = new Intent();
intent.setAction(ACTION);
intent.setPackage(PACK_NAME);//从5.0开始不能隐式调用服务了
bindService(intent,mServiceConn, Context.BIND_AUTO_CREATE);
}
private void initView() {
mTest = (TextView) findViewById(R.id.test);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConn);
}
}
客户端调用AIDL的服务端的过程就这这些了,下一篇文章中一起在看下AIDL的深入分析,以及在调试中遇到的一些问题。
总结:
AIDL的使用其实比较简单,首先在服务端创建AIDL文件,有了这个文件之后系统会自动创建对应的java文件,就如本例中的IMyService.aidl和IMyService.java文件一样,IMyService.java文件中有个Stub的内部类(也称之为桩),该类是一个抽象方法实现了IMyService.aidl生成的接口(其实就是IMyService.java这个接口),但是并没有实现MyService.aidl中的方法,该方法需要在使用是来具体实现,如例中提到的MyServiceImpl这个类继承了Stub并实现了IMyService.aidl中的sayHello()方法。
在客户端调用AIDL时,拷贝一份服务端的AIDL接口是必须的,这个不在强调,最主要的是以Intent的方式去绑定服务,在绑定服务成功后便拿到了之前在服务端的MyServiceImpl对象(IBinder)的代理对象。至此总结完毕。下期继续分析解读系统自动创建的IMyService.java这个文件。