本文共 8288 字,大约阅读时间需要 27 分钟。
前言:回顾一下上一篇博文,上一篇说到,Binder是Android系统中IPC机制的底层依赖,描绘了Binder这种通信架构的基本原理图,并且谈到了使用Binder时需要解决的两个问题。即:1.客户端如何获取Binder对象的引用。2.如何协商服务端的函数标识和参数放入包裹的顺序问题。以便于客户端调用服务时,服务端能识别并提供正确的服务。通过上一篇的介绍,相信大家已经知道了客户端通过Service来获取Binder引用的方式,并且也了解了通过重写服务端Binder的onTransact()方法和客户端Binder的transact()方法来解决上述的第二个问题。对于有经验的程序员,完全可以通过这两种做法来实现IPC通信。于此同时,Google的大神们也为开发者提供了更为方便的AIDL工具,这个工具可以帮我们解决第二个问题,这样,开发者就可以完全专注于业务本身。俗话说:“不做重复的轮子”,既然有这种工具,何乐而不用呢?接下来让我们来走进AIDL。之所以将AIDL放在Binder这里讲,是因为这里着重分析AIDL如何解决Binder通信中的第二个问题。若是这里感觉有点迷糊的话,可以看看上一篇博文
AIDL,全称为Android Interface Definition Language,即android接口定义语言。顾名思义,AIDL只是一种定义语言,用它的规范定义的接口,可以被aidl工具识别并生成对应的类。(aidl工具在sdk中,可以自行查看)。相信这样比较抽象,接下来我们通过一个小小的例子来看看aidl如何工作。
服务端代码,注意与上一篇中的服务端代码进行比较,区别已经在注释中体现出来了。
public class ServerService extends Service { /** * 创建服务端binder对象(不用aidl时需要自定义Binder子类,并在Service中返回) * 并且我们不用在服务端自行书写onTransact()方法 */ private Binder serverBinder = new IMyServerService.Stub() { @Override public void service2(String args) throws RemoteException { System.out.println("---service2---:" + args); } @Override public void service1() throws RemoteException { System.out.println("---service1---"); } }; @Override public void onCreate() { Log.i("DEBUG", "---onCreate()---"); super.onCreate(); } @Override public IBinder onBind(Intent intent) { Log.i("DEBUG", "---onBind()---"); return serverBinder; } @Override public boolean onUnbind(Intent intent) { Log.i("DEBUG", "---onUnbind()---"); return super.onUnbind(intent); }}aidl接口定义,新建com.example.aidl包,新建IMyServerService接口(自行命名),点击保存,可以在gen目录下找到eclipse帮我们自动生成的类IMyServerService.java。之所以新建包,是因为这样等会可以直接将整个包拷贝到客户端中。
package com.example.aidl;interface IMyServerService{ void service1(); void service2(String args);}客户端代码,同样注意与上一篇的比较,同样体现在注释中。
public class ClientActivity extends Activity { private Button btn_connectService; private Button btn_disconnectService; private Button btn_getService1; private Button btn_getService2; // 服务端Service的action,根据自己而变 private Intent intent = new Intent("com.wwt.server.ServerService"); private IMyServerService mService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定服务端 btn_connectService = (Button) findViewById(R.id.btn_connectService); btn_connectService.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { bindService(intent, connection, Context.BIND_AUTO_CREATE); } }); // 取消绑定服务 btn_disconnectService = (Button) findViewById(R.id.btn_disconnectService); btn_disconnectService.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { unbindService(connection); } }); // 获取服务端服务1。在没有aidl的时候,客户端需要编写transact()方法, // 反之则不用。aidl生成的类自动为我们屏蔽了这一细节,即为我们实现了transact()函数。 btn_getService1 = (Button) findViewById(R.id.btn_getService1); btn_getService1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { mService.service1(); } catch (RemoteException e) { e.printStackTrace(); } } }); // 获取服务端服务2 btn_getService2 = (Button) findViewById(R.id.btn_getService2); btn_getService2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { try { mService.service2("Hello"); } catch (RemoteException e) { e.printStackTrace(); } } }); } /** * 通过回调获取Binder对象(可能是服务端的,也可能是Binder驱动中的Binder对象, 取决于本地或是远程调用。) */ private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { // IMyServerService的内部类Stub的asInterface()方法会根据客户端获取到的 // Binder对象的来源来决定调用客户端服务的方式,即是否采用代理。 mService =IMyServerService.Stub.asInterface(service); } };}
服务端不需要界面直接运行,客户端界面比较简单就不写出来了。
运行结果如下:工作是正常的。
打开gen目录,找到aidl工具为我们生成的类,我们发现这个类名字和我们定义的接口名称一致,并且继承了IInterface接口。接下来我们只看关键的代码。
public static abstract class Stub extends android.os.Binder implements com.example.aidl.IMyServerService { private static final java.lang.String DESCRIPTOR = "com.example.aidl.IMyServerService"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.aidl.IMyServerService * interface, generating a proxy if needed. */ public static com.example.aidl.IMyServerService asInterface( android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.example.aidl.IMyServerService))) { return ((com.example.aidl.IMyServerService) iin); } return new com.example.aidl.IMyServerService.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_service1: { data.enforceInterface(DESCRIPTOR); this.service1(); reply.writeNoException(); return true; } case TRANSACTION_service2: { data.enforceInterface(DESCRIPTOR); java.lang.String _arg0; _arg0 = data.readString(); this.service2(_arg0); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.aidl.IMyServerService { 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 service1() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_service1, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void service2(java.lang.String args) 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.writeString(args); mRemote.transact(Stub.TRANSACTION_service2, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_service1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_service2 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); }需要注意的有以下这些点:
可能大家对于上述的第三点胡有点疑虑,即代理类真的有必要存在吗的问题,下面进行简单的验证。将CilentActivity作一点小小的修改,改动如下,直接将客户端获取到的Binder对象进行转型。
mService =IMyServerService.Stub.asInterface(service);
改为: mService =(IMyServerService) service运行结果如下:(类型转换错误,得证)