第一次接触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
接受并处理传来的数据,再把处理得到的数据写入返回值并发送给客户端,客户端读取值后就成为调用方法的返回值返回了。