一 前言
用startService,bindService创建的服务只能在本应用程序内访问,如果要使得本程序的服务能够被其他应用程序访问,这时候就要使用远程过程调用(Remote Procedure Call,RPC)方式来实现,安卓定义了一种接口定义语言Android Interface Definition Language,简称AIDL。今天记录一下如何在Android Studio下创建AIDL Serivce。
建立ADIL Service的步骤比建立普通Service要多一些,主要有:
- 创建AIDL文件(在src/main/aidl/...下,aidl目录需要自己创建),在这里面定义远程接口(例如下面的ICat.adl)。
- Rebuild项目,生成Java接口文件(ICat.java,AS中,这个文件位置在build/generated/source/aidl/debug/目录下),并且在其内部自动生成了一个Stub的内部类,Stub继承了Binder和实现了ICat 接口,因此它可以作为远程Service的回调类。
- 建立一个Service的子类,并且记得在AndroidManifest.xml文件中配置。
在客户端调用ADIL Servie:
- 拷贝服务器端的AIDL文件,并生成Java接口文件。
- 用BindService来调用Service,与调用普通Serivce相类似,只是获取IBinder的方式有点不一样。下面贴出来ICat.java代码
ICat.java代码如下:
package com.sysu.aidlclient.aidlclient;
// Declare any non-default types here with import statements
public interface ICat extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.sysu.aidlclient.aidlclient.ICat {
private static final java.lang.String DESCRIPTOR = "com.sysu.aidlclient.aidlclient.ICat";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.sysu.aidlclient.aidlclient.ICat interface,
* generating a proxy if needed.
*/
public static com.sysu.aidlclient.aidlclient.ICat asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.sysu.aidlclient.aidlclient.ICat))) {
return ((com.sysu.aidlclient.aidlclient.ICat) iin);
}
return new com.sysu.aidlclient.aidlclient.ICat.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_getColor: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getColor();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_getWeight: {
data.enforceInterface(DESCRIPTOR);
double _result = this.getWeight();
reply.writeNoException();
reply.writeDouble(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.sysu.aidlclient.aidlclient.ICat {
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;
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override
public java.lang.String getColor() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getColor, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public double getWeight() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
double _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getWeight, _data, _reply, 0);
_reply.readException();
_result = _reply.readDouble();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getColor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getWeight = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public java.lang.String getColor() throws android.os.RemoteException;
public double getWeight() throws android.os.RemoteException;
二 建立AIDL文件
在项目名称上右键>NEW>AIDL>AIDL File,这样就创建了一个ADIL文件,命名为ICat
文件内容为:
// ICat.aidl
package com.sysu.aidlclient.aidlclient; interface ICat { String getColor(); double getWeight(); }
这一步跟建立普通的Serivce步骤一样,同样右键>New>Service,这样会创建一个Service的子类以及在AndroidManiFest中添加Service的的内容,主要要添加action标签并且定义android:name。它的onBind方法返回的IBinder对象要是ICat.Stub的子类的实例,ICat.Stub这个类基本不用去管它,是自动生成的。
public class AidlService extends Service { private CatBinder catBinder; //此处要继承Stub,实现ICat和IBinder接口 public class CatBinder extends ICat.Stub { @Override public String getColor() throws RemoteException { return "get from remote service"; } @Override public double getWeight() throws RemoteException { return 999.9; } } @Override public void onCreate() { super.onCreate(); <span style="color:#ff0000;">catBinder = new CatBinder(); @Override public IBinder onBind(Intent intent) { <span style="color:#ff0000;">return catBinder; } @Override public void onDestroy() { System.out.println("remote service destroy"); } }
三 客户端调用
首先要拷贝AIDL文件,这里要保证文件的内容一模一样,包括包的名称,比如本例子中服务器端AIDL文件所在包的名称是com.sysu.aidlclient.aidlcilent,如何做到这一点,先新建一个项目,然后在:项目文件夹/app/src/main目录下建立一个aidl文件夹,与java文件夹同级,在Android Studio中就可以看到这个目录,在这个目录上右键New>Package,建立一个com.sysu.aidlclient.aidlclient的包,再将aidl文件拷进去。这样才能保证生成的java接口文件完全一样,否则会提示找不到接口。
在MainActivity中调用,用bindService方法,记得要定义一个显式的intent,如红色代码获取Service的IBinder的代理
private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { catService = ICat.Stub.asInterface(service);</span> } @Override public void onServiceDisconnected(ComponentName name) { catService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); intent.setAction("com.sysu.aidlclient.action.AIDL_SERVICE"); //this is important intent.setPackage("com.sysu.aidlclient.aidlclient"); bindService(intent,conn, Service.BIND_AUTO_CREATE); }
public void getRemoteService(View view) { try { Toast.makeText(this,"the color and weight is: "+catService.getColor()+":", Toast.LENGTH_LONG).show(); System.out.println(catService.getColor()+"----"+catService.getWeight()); }catch (RemoteException e) { e.printStackTrace(); } System.out.println("button click"); }