在上一篇中,最后我们为了安全,隐藏了中间人,只是暴露了一个接口。
那么今天我们来说说aidl远程绑定Service这回事。没看过上一篇的请先移步我上一篇 Service绑定(上)
定义接口
其实很简单,我们只要把上一篇的IMiddlePerson这个接口文件后缀名改成aidl就可以了。
IMiddlePerson.java -> IMiddlePerson.aidl
改成这样后,系统会帮我们在build目录下(studio是build目录,eclipse是gen目录下)自动生成一个IMiddlePerson.java文件,这个文件如下:
/*
* This file is auto-generated. DO NOT MODIFY.
*
*/
package com.zyp.testservice.service;
/**
* Created by ZYP on 2017/3/26 0026.
*/
public interface IMiddlePerson extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.zyp.testservice.service.IMiddlePerson
{
private static final java.lang.String DESCRIPTOR = "com.zyp.testservice.service.IMiddlePerson";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.zyp.testservice.service.IMiddlePerson interface,
* generating a proxy if needed.
*/
public static com.zyp.testservice.service.IMiddlePerson asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.zyp.testservice.service.IMiddlePerson))) {
return ((com.zyp.testservice.service.IMiddlePerson)iin);
}
return new com.zyp.testservice.service.IMiddlePerson.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_handleThings:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
this.handleThings(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.zyp.testservice.service.IMiddlePerson
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void handleThings(int money) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(money);
mRemote.transact(Stub.TRANSACTION_handleThings, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_handleThings = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void handleThings(int money) throws android.os.RemoteException;
}
这乱七八糟的一堆是什么东西?没事我们看主要的东西:
/*
* This file is auto-generated. DO NOT MODIFY.
* */
public interface IMiddlePerson extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.zyp.testservice.service.IMiddlePerson
{
/**
* Cast an IBinder object into an com.zyp.testservice.service.IMiddlePerson interface,
* generating a proxy if needed.
*/
public static com.zyp.testservice.service.IMiddlePerson asInterface(android.os.IBinder obj)
{}
}
public void handleThings(int money) throws android.os.RemoteException;
}
看以上简略代码,看首行注释,那是studio自动生成的,告诉我们“DO NOT MODIFY”。
然后我们看到这个自动生成的IMiddlePerson.java类主要就是生成了一个内部类,继承Binder接口,并实现了我们定义的IMiddlePerson接口;而且handleThings()方法也是有的。
asInterface()方法看注释即可明白,他把一个IBinder对象强制转成一个我们对应包下的IMiddlePerson对象。
好了,我们该要的准备工作都已经完成。接下来我们建个项目试试;
建立远程项目Service
现在我们先建立一个RemoteService项目,
如上图,MainActivity里什么都没有,一个IMiddlePerson的aidl接口,一个RemoteService,
Service代码如下:
public class RemoteService extends Service {
@Override
public void onCreate() {
Log.e(RemoteService.class.getSimpleName(),"服务被创建了");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(RemoteService.class.getSimpleName(),"服务启动了");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(RemoteService.class.getSimpleName(),"服务被销毁了");
super.onDestroy();
}
private class MiddlePerson extends IMiddlePerson.Stub {
@Override
public void handleThings(int money) {
if(money > 200){
callLingDao();//请求领导办事
}else{
Toast.makeText(getApplicationContext(),"多准备点钱吧",Toast.LENGTH_SHORT).show();
}
}
public void playMajiang(){
}
}
public void callLingDao(){
Log.e(RemoteService.class.getSimpleName(),"项目帮你批好了!");
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new MiddlePerson();
}
}
IMiddlePerson.aidl接口:
interface IMiddlePerson {
void handleThings(int money);
}
建立本地项目
我们再建立一个本地项目
然后把远程项目RemoteService里面的aidl文件连同完整的包路径都复制到这个项目,
本地的aidl文件要和远程的aidl文件所在文件路径都要完全一致,这样最后在ServiceConnection中强转IBinder类型到IMiddlePerson接口类时候才不会报错。
在本地项目中写入绑定远程服务的代码:
public void bindRemoteService(){
//这里要用到隐示启动了
Intent intent = new Intent("com.test.remoteservice");
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG,"bind succeed");
//
IMiddlePerson mp = IMiddlePerson.Stub.asInterface(service);
//调用中间人的方法
try {
mp.handleThings(500);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG,"Disconnected");
}
};
bindService(intent,conn,BIND_AUTO_CREATE);
}
至此我们运行远端项目,然后运行本地项目,接着绑定远端Service,流程基本通了。
总结
aidl:android interface definetion language 安卓接口定义语言
aidl语言是没有访问修饰符的。
aidl都是公有的
流程:
1、在服务创建一个内部类,继承Binder,提供方法,访问服务内部的方法;
2、把暴露的接口文件文件的扩展名改成aidl文件,去掉访问修饰符public
(该接口文件用于定义服务的内部类里面的方法。)
private class MyBinder extends IMyBinder.Stub{} IPC的子类
3、实现服务的onBind()方法,返回MyBinder;
4、在antivity中绑定服务,bindService();
5、在服务成功绑定时候,会执行一个方法onServiceConnected(),传递过来一个IBinder对象;
6、IMyBinder.Stub.adInterface(binder)调用接口里面的方法,强转成你定义的接口。