此篇继续详解Android AIDL知识
1.AIDL简介
AIDL:Android Interface Definition Language,即Android接口定义语言。
Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。
为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。
2.建立AIDL服务的步骤
建立AIDL服务要比建立普通的服务复杂一些,具体步骤如下:
(1)在Eclipse Android工程的Java包目录中建立一个扩展名为aidl的文件。该文件的语法类似于Java代码,但会稍有不同。
(2)如果aidl文件的内容是正确的,ADT会自动生成一个Java接口文件(*.java)。
(3)建立一个服务类(Service的子类)。
(4)实现由aidl文件生成的Java接口。
(5)在AndroidManifest.xml文件中配置AIDL服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的ID,也就是Intent类的参数值。
实现AIDL接口的说明:
(1)AIDL接口只支持方法,不能声明静态成员; (2)不会有返回给调用方的异常。
3.具体实现demo(IDE Eclipse) 3.1.创建aidl文件 3.1.1.选择你要建立的aidl文件所在的包 3.1.2.然后File->New->File,弹出对话框 输入XXX.aidl(必须以aidl结尾) 3.1.3.最后,finish即可。 3.1.4.然后在aidl文件中给出正确的aidl接口代码,保存。系统会自动生成其实现类源文件:XXX.java(在gen下) 此时说明第一步创建aidl文件成功 如下图
3.1.5.aidl 接口代码举例
package com.example.eventbusdemo.aidl.server; interface MyAIDL{ boolean issuccess(); String getName(); String getAge(); } 3.2.自动生成的aidl文件代码如下 /* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\Users\\Administrator\\newworkspace\\EventBusDemo\\src\\com\\example\\eventbusdemo\\aidl\\server\\MyAIDL.aidl */ package com.example.eventbusdemo.aidl.server; public interface MyAIDL extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.eventbusdemo.aidl.server.MyAIDL { private static final java.lang.String DESCRIPTOR = "com.example.eventbusdemo.aidl.server.MyAIDL"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.eventbusdemo.aidl.server.MyAIDL interface, * generating a proxy if needed. */ public static com.example.eventbusdemo.aidl.server.MyAIDL asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.eventbusdemo.aidl.server.MyAIDL))) { return ((com.example.eventbusdemo.aidl.server.MyAIDL)iin); } return new com.example.eventbusdemo.aidl.server.MyAIDL.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_issuccess: { data.enforceInterface(DESCRIPTOR); boolean _result = this.issuccess(); reply.writeNoException(); reply.writeInt(((_result)?(1):(0))); return true; } case TRANSACTION_getName: { data.enforceInterface(DESCRIPTOR); java.lang.String _result = this.getName(); reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_getAge: { data.enforceInterface(DESCRIPTOR); java.lang.String _result = this.getAge(); reply.writeNoException(); reply.writeString(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.eventbusdemo.aidl.server.MyAIDL { 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 issuccess() 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); mRemote.transact(Stub.TRANSACTION_issuccess, _data, _reply, 0); _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.lang.String getName() 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_getName, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.lang.String getAge() 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_getAge, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_issuccess = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_getAge = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); } public boolean issuccess() throws android.os.RemoteException; public java.lang.String getName() throws android.os.RemoteException; public java.lang.String getAge() throws android.os.RemoteException; }
自动生成的java代码比较多 也比较乱 不过 我们仔细看看主要的几个
Proxy,Stub和asInterface。
3.2.1.Proxy(类)实现了刚刚定义的aidl中的接口
private static class Proxy implements com.example.eventbusdemo.aidl.server.MyAIDL { 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 issuccess() 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); mRemote.transact(Stub.TRANSACTION_issuccess, _data, _reply, 0); _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.lang.String getName() 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_getName, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.lang.String getAge() 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_getAge, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } }
即此类实现了刚刚定义的aidl接口(interface MyAIDL) 重写实现了其中定义好的三个方法
boolean issuccess(); String getName(); String getAge();
3.2.Stub(抽象类)
public static abstract class Stub extends android.os.Binder implements com.example.eventbusdemo.aidl.server.MyAIDL{ } 详细代码 /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.eventbusdemo.aidl.server.MyAIDL { private static final java.lang.String DESCRIPTOR = "com.example.eventbusdemo.aidl.server.MyAIDL"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.eventbusdemo.aidl.server.MyAIDL interface, * generating a proxy if needed. */ public static com.example.eventbusdemo.aidl.server.MyAIDL asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.eventbusdemo.aidl.server.MyAIDL))) { return ((com.example.eventbusdemo.aidl.server.MyAIDL)iin); } return new com.example.eventbusdemo.aidl.server.MyAIDL.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_issuccess: { data.enforceInterface(DESCRIPTOR); boolean _result = this.issuccess(); reply.writeNoException(); reply.writeInt(((_result)?(1):(0))); return true; } case TRANSACTION_getName: { data.enforceInterface(DESCRIPTOR); java.lang.String _result = this.getName(); reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_getAge: { data.enforceInterface(DESCRIPTOR); java.lang.String _result = this.getAge(); reply.writeNoException(); reply.writeString(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.eventbusdemo.aidl.server.MyAIDL { 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 issuccess() 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); mRemote.transact(Stub.TRANSACTION_issuccess, _data, _reply, 0); _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.lang.String getName() 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_getName, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.lang.String getAge() 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_getAge, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_issuccess = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_getAge = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); }
3.2.3.asInterface(方法)
public static com.example.eventbusdemo.aidl.server.MyAIDL asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.eventbusdemo.aidl.server.MyAIDL))) { return ((com.example.eventbusdemo.aidl.server.MyAIDL)iin); } return new com.example.eventbusdemo.aidl.server.MyAIDL.Stub.Proxy(obj); }
Proxy 这里是private权限的,外部是无法访问的,但这里是 Android 有意为之,抛出了 asInterface 方法,这样避免了对 Proxy可能的修改。即此方法公外部访问。
3.2.4总结
Proxy 是写入参数,读取值;Stub 是读取参数,写入值。正好是一对,即Proxy 和 Stub 操作的是一份数据。
3.3.创建服务
public class MyService extends Service{ @Override public IBinder onBind(Intent arg0) { return stub; } MyAIDL.Stub stub=new MyAIDL.Stub(){ @Override public boolean issuccess() throws RemoteException { return false; } @Override public String getName() throws RemoteException { return "张三"; } @Override public String getAge() throws RemoteException { return "28"; } }; }
3.4.java代码中使用
package com.example.eventbusdemo.aidl.client; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import com.example.eventbusdemo.R; import com.example.eventbusdemo.aidl.server.MyAIDL; import com.example.eventbusdemo.aidl.server.MyService; public class AIDLActivity extends Activity{ private Button btn; private MyAIDL myService=null; private ServiceConnection serviceConnection; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_aidl); bindService();//绑定服务 btn=(Button) findViewById(R.id.activity_aidlbtn); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { if(null!=myService){ try { String name=myService.getName(); String age=myService.getAge(); boolean issuccess=myService.issuccess(); Log.d("AIDLActivity", "name----:"+name); Log.d("AIDLActivity", "age----:"+age); Log.d("AIDLActivity", "issuccess----:"+issuccess); } catch (RemoteException e) { e.printStackTrace(); } } } }); } //绑定服务 public void bindService(){ serviceConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName arg0, IBinder arg1) { myService=MyAIDL.Stub.asInterface(arg1); Log.d("AIDLActivity", "onServiceConnected!!!!!!!!!!!!"); } @Override public void onServiceDisconnected(ComponentName arg0) { Log.d("AIDLActivity", "onServiceDisconnected!!!!!!!!!!!!"); } }; //可有可无 // bindService(new Intent("com.example.eventbusdemo.aidl.server.MyAIDL"), serviceConnection, Context.BIND_AUTO_CREATE); Intent intent=new Intent(AIDLActivity.this,MyService.class); bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); } }
3.5.结果