服务(Service)是Android的四大组件之一,它利用底层Binder机制,实现了RPC机制。 一个服务即可以存在于一个独立的进程,也可以依附于已存在的某个进程中。服务可被同一进程中的Activity调用,也可以被位于不同进程中的某个Activity调用。 本文主要探讨怎样编写一个远程服务接口的过程。为演示作用,本文不介绍通过AIDL语言自动生成服务接口代码的过程。
首先,我们定义接口:
public interface IRemoteService extends IInterface {
/**
* serviceMethod
*/
public void serviceMethod(int arg0, float arg1, long arg2, boolean arg3, double arg4, String arg5) throws RemoteException;
}
需要说明的是,由于受Binder机制的约束,除基本数据类型外,对于自定义的数据类型,必须实现Parceable接口,才能作为服务方法的参数。本文将不考虑自定义类型作为参数传递的情况。
接下来的重点就是实现上述定义的服务接口,这里,为了支持同一进程和不同进程的Activity都能够调用该服务接口,我们需要两个接口实现,一个是本地实现,一个是远程实现。在介绍这两个实现代码之前,我们先看下对应的RemoteService类的实现:
public RemoteService extends Service {
@Override
public void onCreate() {
}
@Override
public void onDestroy() {
}
@Override
public IBinder onBind(Intent intent) {
// Select the interface to return. If your service only implements
// a single interface, you can just return it here without checking
// the Intent.
if (IRemoteService.class.getName().equals(intent.getAction())) {
return mBinder;
}
return null;
}
/**
* The IRemoteInterface is defined through IDL
*/
private final RemoteServiceStub mBinder = new RemoteServiceStub() {
public void serviceMethod(int arg0, float arg1, long arg2, boolean arg3, double arg4, String arg5)
{
//do something here
}
};
}
在Android App开发中,定义自己的服务需要从Service类中派生,启动一个Service可以通过startService,也可以通过bindService, 对于通过bindService调用一个服务接口的方式,同时需要实现onBind()方法,它返回的IBinder对应就是我们下面将要介绍的服务实现类。
首先是本地接口实现类,代码如下:
/** Local-side IPC implementation stub class. */
public abstract class RemoteServiceStub extends Binder implements IRemoteService {
private static final String DESCRIPTOR = "com.fyj.test.IRemoteService";
/** Construct the stub at attach it to the interface. */
public RemoteServiceStub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an
* com.fyj.test.IRemoteService interface, generating a
* proxy if needed.
*/
public static IRemoteService asInterface(IBinder obj) {
if ((obj == null)) {
return null;
}
IInterface iin = (android.os.IInterface) obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IRemoteService))) {
return ((IRemoteService) iin);
}
return new RemoteServiceProxy(obj);
}
public IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_methodService: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
float _arg1;
_arg1 = data.readFloat();
long _arg2;
_arg2 = (0!=data.readLong());
boolean _arg3;
_arg3 = data.readInt()?true:false;
double _arg4;
_arg4 = data.readDouble();
String _arg5;
_arg5 = data.readString();
this.serviceMethod(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
public void serviceMethod(int arg0, float arg1, long arg2, boolean arg3, double arg4, String arg5) throws RemoteException;
static final int TRANSACTION_methodService = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
它实现为一个抽象类,将接口的具体实现延迟到RemoteService中去实现。在本类 中,主要实现了onTransact()方法,它将处理客户的调用请求。asInterface()接口将自动判断当前是本地调用还是远程调用,如果是远程调用,将使用 RemoteServiceProxy类的实例的接口调用服务,它的实现代码如下:
/** Local-side IPC implementation stub class. */
public class RemoteServiceProxy implements IRemoteService {
private static final String DESCRIPTOR = "com.fyj.test.IRemoteService";
private IBinder mRemote;
RemoteServiceProxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
public void serviceMethod(int arg0, float arg1, long arg2, boolean arg3, double arg4, String arg5) throws RemoteException
{
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeFloat(aFloat);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(TRANSACTION_methodService, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
static final int TRANSACTION_methodService = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
该类是代理类,对服务的调用者是透明的。
在调用bindService的过程中,需要传递一个ServiceConnection对象,该对象将在服务连接成功后,会接收到服务类的对象,以此可以判断当前应该使用本地服务类实现,还是远程服务类实现,关于具体的实现细节,将另外专题分析。 下面给出ServiceConnection对象实现创建的代码:
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// TODO Auto-generated method stub
mService = RemoteServiceStub.asInterface(service);
...
}
public void onServiceDisconnected(ComponentName className) {
// TODO Auto-generated method stub
mService = null;
...
}
};