第一次接触aidl
的时候,就感觉这个很难,对于我一个Android小白来说,理解他的原理也没什么必要,觉得会用就行。
其实一步步看,也是蛮简单的。
aidl的使用
最常见的aidl
的使用就是
Service
的跨进程通信了,那么我们就写一个
Activity
和
Service
的跨进程通信吧。
首先,我们就在AS里面新建一个aidl
文件(ps:现在AS建aidl
不要求和java包名相同了):
interface IMyAidlInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); String getInfor(String s); }
basicTypes方法可以不用去管它,我们在这自己定义了一个getInfor()方法,接受一个字符串参数,然后返回一个字符串,恩,相当的简单。
接着我们sync project一下就可以下app/generated/source/aidl/debug/aidl
里面发现由aidl生成的java文件,这是由AS自动生成的,先上代码
package com.example.haley.coolweather; // Declare any non-default types here with import statements public interface IMyAidlInterface extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.haley.coolweather.IMyAidlInterface { private static final java.lang.String DESCRIPTOR = "com.example.haley.coolweather.IMyAidlInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.haley.coolweather.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.example.haley.coolweather.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.haley.coolweather.IMyAidlInterface))) { return ((com.example.haley.coolweather.IMyAidlInterface)iin); } return new com.example.haley.coolweather.IMyAidlInterface.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_basicTypes: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); long _arg1; _arg1 = data.readLong(); boolean _arg2; _arg2 = (0!=data.readInt()); float _arg3; _arg3 = data.readFloat(); double _arg4; _arg4 = data.readDouble(); java.lang.String _arg5; _arg5 = data.readString(); this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); reply.writeNoException(); return true; } case TRANSACTION_getInfor: { data.enforceInterface(DESCRIPTOR); java.lang.String _arg0; _arg0 = data.readString(); java.lang.String _result = this.getInfor(_arg0); reply.writeNoException(); reply.writeString(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.haley.coolweather.IMyAidlInterface { 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 void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.writeInt(anInt); _data.writeLong(aLong); _data.writeInt(((aBoolean)?(1):(0))); _data.writeFloat(aFloat); _data.writeDouble(aDouble); _data.writeString(aString); mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public java.lang.String getInfor(java.lang.String s) 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); _data.writeString(s); mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException; public java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException; }
这里面的代码长的一笔,我们先不用去看他,我们先看一下service
public class MyService extends Service { public final static String TAG = "MyService"; private IBinder binder = new IMyInterface.Stub() { @Override public String getInfor(String s) throws RemoteException { Log.i(TAG, s); return "我是 Service 返回的字符串"; } }; @Overrid public void onCreate() { super.onCreate(); Log.i(TAG, "onCreat"); } @Override public IBinder onBind(Intent intent) { return binder; } }
在这,我们先new了一个ImyInterface.stub(),并向上转型为IBinder,在inBInder()方法中返回,同时重写了我们上面定义的抽象方法,我们可以在上面看到,ImyInterface.stub是ImyInterface的一个内部类,他继承了Binder,并且实现了我们刚刚定义的接口。生成的.java文件中,大部分的代码都是这个内部类。
因为是跨进程通信,所以还需要在AndroidManifest.xml文件中,声明service时加上一个process属性,如图
<service android:name=".server.MyService" android:process="com.mathiasluo.remote" />
我们接着看Activity
public class MainActivity extends AppCompatActivity { public final static String TAG = "MainActivity"; private IMyInterface myInterface; private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { myInterface = IMyInterface.Stub.asInterface(service); Log.i(TAG, "连接Service 成功"); try { String s = myInterface.getInfor("我是Activity传来的字符串"); Log.i(TAG, "从Service得到的字符串:" + s); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, "连接Service失败"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startAndBindService(); } private void startAndBindService() { Intent service = new Intent(MainActivity.this, MyService.class); //startService(service); bindService(service, serviceConnection, Context.BIND_AUTO_CREATE); } }
首先,我们因该明白的是,传回来的IBinder
就是我们在Service
的onBind( )
方法所return
的IBinder
,然后我们调用Stub
中的静态方法asInterface
并把返回来的IBinder
当参数传进去。
在asInterface
方法中,首先判断了传进来的IBinder
是不是null
,如果为null
就返回一个null
;接着就判断传进来的IBinder
是不是就在当前进程里面,如果是的话就直接返回IMyInterface
,不是的话就返回IMyInterface.Stub.Proxy(obj)
。这里我觉得需要明白的是:直接返回的IMyInterface
是实现了定义的接口方法getInfor
的。因为在IMyInterface.Stub
中所实现的。当然如果是在同一进程中,那么我们调用IMyInterface
的方法时就是在本地调用方法,直接调用就可以了。
如果没在同一进程,就会返回IMyInterface.Stub.Proxy(obj)
:
接着在Proxy这个静态内部类中,这里我们调用了IBinder
的transact
方法,来把数据传给远端的服务器。然后在我们远程的MyService
中,里面的Stub
中就会回调onTransact()
(因为你把数据传个远程的服务,远端的服务收到数据也就回调了)
所以,当我们简单的调用IMyInterface
的getInfor
时候,先是Proxy
的transact
发送出数据,然后服务端的onTransact
接受并处理传来的数据,再把处理得到的数据写入返回值并发送给客户端,客户端读取值后就成为调用方法的返回值返回了。