设想这么一个场景,我们有2个APP(或者2个进程,均可),其中一个APP需要提供一个Person相关的服务(该服务有一个名为eat的接口),我们叫它PersonServer;另一个APP需要访问PersonServer提供的服务,我们叫它Client。也就是现在有2个APP,一个作为Server端,提供服务,另一个作为Client端,使用服务。
我们来看如何在Android中实现?
PersonServer端实现PersonServer端是服务的提供者,我们首先需要创建一个Service来提供该服务,并且需要该服务具备跨进程通信的能力,以便Client端进行调用。
实现AIDL跨进行,我们首先想到的是使用AIDL来实现接口的跨进程能力。
首先我们需要定义一个名为IPerson的AIDL接口,并提供eat方法:
package com.testaidl;
interface IPerson {
boolean eat(String food);
}
我们看到,IPerson的实现非常简单,我们使用IDE编译一下,编译器就会生成一个名为IPerson.java的文件,即aidl所对应的java代码。
实现Service接下来我们定义一个Service:
public class PersionService extends Service
{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new IPerson.Stub() {
@Override
public boolean eat(String food) throws RemoteException {
Log.d("PersionService", "this is Server");
Log.d("PersionService", "Persion eat " + food);
return true;
}
};
}
}
这里重点来看onBind方法,该方法返回一个IBinder对象,这里也就是之前我们定义的IPerson.aidl的生成类IPerson.Stub,IPerson.Stub类有一个抽象方法eat()需要在这里实现,这里也就是该服务所提供的远程服务所执行动作的具体实现。
别忘了在AndroidManifest中注册:
Client端
Server端已经准备好了,那么Client端如何访问PersonServer所提供的服务呢?
我们来看Client端的实现:
public class MainActivity extends AppCompatActivity {
private IPerson mService = null;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //绑定Service成功后执行
mService = IPerson.Stub.asInterface(iBinder);//获取远程服务的代理对象,一个IBinder对象
try {
mService.eat("banana"); //调用远程服务的接口。
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bindService = findViewById(R.id.bind_service);
bindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//调用bindService发送绑定远程服务的请求
Intent intent = new Intent();
intent.setAction("com.example.simpledemo.PersionService");
intent.setPackage("com.example.simpledemo");
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
});
}
}
步骤分析:
调用bindService发送绑定远程服务的请求。
ServiceConnection对象在绑定Service后执行回调函数onServiceConnected。
在onServiceConnected中,获取远程服务的代理对象,一个IBinder对象。
最后,通过上一步获取的远程服务代理对象,调用远程服务的接口。
注意
别忘了需要在Client端的同样位置,放置IPerson.aidl文件,包名,文件名等都保持一致。
Service/AIDL远程调用过程解析在Serivce的远程通信过程中,最关键的点就是AIDL,它承担了远程通信访问的任务,它的低层实现当然也是通过Binder机制来实现的,但是AIDL于Binder相比,简化了我们的使用。
IPerson.aidl我们首先来看IPerson.aidl:
package com.testaidl;
interface IPerson {
boolean eat(String food);
}
它的实现非常简单,那它是怎么实现远程通信的能力的呢?
我们知道,aidl文件经过编译器编译后,会生成一个.java文件,这个java文件才是真正存放远程通信实现逻辑代码的地方。
IPerson.java:
package com.testaidl;
// Declare any non-default types here with import statements
public interface IPerson extends android.os.IInterface
{
public static abstract class Stub extends android.os.Binder implements com.testaidl.IPerson
{
private static final java.lang.String DESCRIPTOR = "com.testaidl.IPerson";
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
public static com.testaidl.IPerson asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.testaidl.IPerson))) {
return ((com.testaidl.IPerson)iin);
}
return new com.testaidl.IPerson.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
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_eat:
{
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
boolean _result = this.eat(_arg0);
reply.writeNoException();
reply.writeInt(((_result)?(1):(0)));
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.testaidl.IPerson
{
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 boolean eat(java.lang.String food) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(food);
boolean _status = mRemote.transact(Stub.TRANSACTION_eat, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().eat(food);
}
_reply.readException();
_result = (0!=_reply.readInt());
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.testaidl.IPerson sDefaultImpl;
}
static final int TRANSACTION_eat = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
public static boolean setDefaultImpl(com.testaidl.IPerson impl) {
if (Stub.Proxy.sDefaultImpl == null && impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.testaidl.IPerson getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public boolean eat(java.lang.String food) throws android.os.RemoteException;
}
我们定义aidl时,也只用了几行代码,而这个生成的java类里面,代码还是非常多的。
我们首先来看它的类结构:
原创文章 15获赞 1访问量 4151
关注
私信
展开阅读全文
作者:卜大爷