AIDL服务简介
Android的远程Service调用与Java的RMI基本相似,一样都是先定义一个远程调用接口,然后为该接口提供一个实现类即可。
与RIM不同的是,客户端访问Service时,Android并不是直接返回Service对象给客户端——这一点绑定本地Service时已经看到,Service只是将一个回调对象(IBinder对象)通过onBind()方法返回给客户端。因此Android的AIDL远程接口的实现类就是那个IBinder实现类。
与绑定本地Service不同的是,本地Service的onBind()方法会直接把IBinder对象本身传给客户端的ServiceConnention的onServiceConnected方法的第二个参数。但远程Service的onBind()方法只是将IBinder对象的代理传给客户端的ServiceConnection的onServiceConnected方法的第二个参数。
当客户端获取了远程Service的IBinder对象的代理之后,接下来就通过该IBinder对象去调用远程Service的属性或方法了。
创建AIDL文件
AIDL的语法与Java接口很相似,但存在如下差异:
1.AIDL定义接口的源代码必须以.aidl结尾
2.AIDL接口中用到的数据类型,除了基本类型、String、List、Map、CharSequence之外,其他类型全部都需要导包,即使他们在同一个包中也需要导包。
开发人员定义的AIDL接口只是定义了进程之间的通信接口,Service端、客户端都需要使用Android SDK安装目录下的platform-tools子目录下的aidl.exe工具为该接口提供实现。如果开发者使用ADT工具进行开发,那么ADT工具会自动为该AIDL接口生成实现。
Android Studio直接右键--new--AIDL--AIDL File
package com.hello.myandroidtest.service;
interface ICat {
String getColor();
double getWeight();
}
定义好上面的接口后,ADT工具会自动生成一个ICat.Java接口,在该接口里包含一个Stub内部类,该内部类实现了IBinder、ICat两个接口,这个Stub类将会作为远程Service的回调类——它实现了IBinder接口,因此可作为Service的onBinder()方法返回值。
将接口暴露给客户端
上一步定义好AIDL接口之后,接下来就可定义一个Service实现类了,该Service的onBind()方法所返回的IBinder对象应该是应该是ADT所生成的ICat.Stub的子类的实例。至于其他部分,则与开发本地Service完全一样。
public class AidlService extends Service {
private CatBinder catBinder;
Timer timer = new Timer();
String[] colors = new String[]{
"红色",
"黄色",
"黑色"
};
double[] weights = new double[]{
2.3,
3.1,
1.58
};
private String color;
private double weight;
//继承Stub,也就是实现了ICat接口,并实现了IBinder接口
public class CatBinder extends ICat.Stub{
@Override
public String getColor() throws RemoteException {
return color;
}
@Override
public double getWeight() throws RemoteException {
return weight;
}
}
@Override
public void onCreate() {
super.onCreate();
catBinder = new CatBinder();
timer.schedule(new TimerTask() {
@Override
public void run() {
//随机地改变Service组件内color、weight属性值
int rand = (int) (Math.random() * 3);
color = colors[rand];
weight = weights[rand];
System.out.println("------" + rand);
}
}, 0, 800);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
/*
* 返回catBinder对象
*
* 在绑定本地Service的情况下,该catBinder对象会直接
* 传给客户端的ServiceConnection
* 的onServiceConnected方法的第二个参数
*
* 在绑定远程Service的情况下,只将catBinder对象的代理
* 传给客户端的ServiceConnection对象
* 的onServiceConnected方法的第二个参数
*/
return catBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
}
}
清单配置文件
<service android:name=".service.AidlService">
<intent-filter>
<action android:name="com.myandroid.service.AIDL_SERVICE"/>
</intent-filter>
</service>
客户端访问AIDLService
public class Activity27 extends BaseActivity {
private ICat catService;
Button get;
TextView color, weight;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//获取远程Service的onBind方法返回的对象的代理
catService = ICat.Stub.asInterface(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
catService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity27);
get = findViewById(R.id.get);
color = findViewById(R.id.color);
weight = findViewById(R.id.weight);
/*
* 服务意图必须是显性声明。 这是为了防止造成冲突(有多个Service用同样的intent-filter的情况)
* 这是Android 5.0 (Lollipop) 之后的规定。不能用包名的方式定义Service Intent, 而要用显
* 性声明:new Intent(context, xxxService.class);
*
* 如果想继续使用隐式意图的话,加上包名信息即可
*/
//创建绑定服务的Intent
Intent intent = new Intent();
intent.setAction("com.myandroid.service.AIDL_SERVICE");
intent.setPackage(context.getPackageName());//兼容Android 5.0
bindService(intent, conn, Service.BIND_AUTO_CREATE);
get.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try{
color.setText(catService.getColor());
weight.setText(String.valueOf(catService.getWeight()));
}catch (Exception e){
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
this.unbindService(conn);
}
}
网友评论