AIDL简单使用
2016-09-19 11:29
211 查看
AIDL是Android Interface Definition Language, 顾名思义,它主要就是用来定义接口的一种语言。Android提供AIDL主要用来进程间通讯。
从AIDL的功能来看,它主要的应用场景就是IPC。虽然同一个进程中的client-service也能够通过AIDL定义接口来进行通信,但这并没有发挥AIDL的主要功能。 概括来说:
如果不需要IPC,那就直接实现通过继承Binder类来实现客户端和服务端之间的通信。
如果确实需要IPC,但是无需处理多线程,那么就应该通过Messenger来实现。Messenger保证了消息是串行处理的,其内部其实也是通过AIDL来实现。
在有IPC需求,同时服务端需要并发处理多个请求的时候,使用AIDL才是必要的
AIDL的简单使用步骤如下:
编写.AIDL文件,定义需要的接口
实现定义的接口
将接口暴露给客户端调用
下面在AS上创建一个工程来使用一下:
创建Aidl文件:
创建完后,可以看到aidl接口文件里面已经为我们提供了案例:
// IMyAidlInterface.aidl
package com.example.aidltest;
// Declare any non-default types here with import statements
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);
}这里先说下AIDL支持下列所述的数据类型:
所有的基本类型(int、float等)
String
CharSequence
List
Map
如果要使用自定义的类型,必须实现
下面自定义HelloMsg类:
定义好
注意到
接下来还需要修改IMyAidlInterface.aidl文件,如下:
即便
注意:build之后发现会报错,将IHelloMsgInterfece.aidl重命名为HelloMsg.aidl即可。
build成功之后会在build/generated/souce/aidl/debug目录下生成IMyAidlInterface文件。可以大致熟悉下该文件的内容,对掌握android binder机制很有帮助
这里有个内部类Stub,它继承系统Binder类和实现IMyAidlInterface接口。另外还提供了asInterface()接口,这个方法接受一个远端
上面看完了Stub类之后,发现他其实是远端服务Binder对象的一个中间者,用来和客户端进行交互的,下面再来看一下Proxy类:
可以看到里面有个mRemote对象,它是服务端传递过来的binder对象。调用transact方法后会调用上面Stub中的onTransact方法。这里其实用了静态代理模式,Proxy就是远端传递过来的binder的本地代理。可以理解为客户端的中间者。
Stub类是服务端的中间者,一般是实现了AIDL接口类型和继承了Binder类,具备将Binder对象转化成原生对象的能力
Proxy类是客户端的中间者,一般是实现了AIDL接口类型
下面实现服务端的接口,定义RemoteService.java
客户端调用服务端接口代码如下:
在
在这里我为RemoteService设置了process属性,让它运行在与默认进程不同的进程中。
从上图可看出客户端和服务运行在两个进程当中。
然后点击按钮,成功返回结果。
最后给出一张流程图,加深印象:
关于AIDL和binder机制可参考下面文章:
Android中AIDL的基本用法
Binder机制和远程服务调用机制分析
从AIDL的功能来看,它主要的应用场景就是IPC。虽然同一个进程中的client-service也能够通过AIDL定义接口来进行通信,但这并没有发挥AIDL的主要功能。 概括来说:
如果不需要IPC,那就直接实现通过继承Binder类来实现客户端和服务端之间的通信。
如果确实需要IPC,但是无需处理多线程,那么就应该通过Messenger来实现。Messenger保证了消息是串行处理的,其内部其实也是通过AIDL来实现。
在有IPC需求,同时服务端需要并发处理多个请求的时候,使用AIDL才是必要的
AIDL的简单使用步骤如下:
编写.AIDL文件,定义需要的接口
实现定义的接口
将接口暴露给客户端调用
下面在AS上创建一个工程来使用一下:
创建Aidl文件:
创建完后,可以看到aidl接口文件里面已经为我们提供了案例:
// IMyAidlInterface.aidl
package com.example.aidltest;
// Declare any non-default types here with import statements
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);
}这里先说下AIDL支持下列所述的数据类型:
所有的基本类型(int、float等)
String
CharSequence
List
Map
如果要使用自定义的类型,必须实现
Parcelable接口才能进行进程间通讯。
下面自定义HelloMsg类:
public class HelloMsg implements Parcelable { private String name; private int age; public HelloMsg(String name, int age) { this.name = name; this.age = age; } protected HelloMsg(Parcel in) { name = in.readString(); age = in.readInt(); } public static final Creator<HelloMsg> CREATOR = new Creator<HelloMsg>() { @Override public HelloMsg createFromParcel(Parcel in) { return new HelloMsg(in); } @Override public HelloMsg[] newArray(int size) { return new HelloMsg[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); } @Override public String toString() { return "HelloMsg{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
定义好
HelloMsg.java之后,还需要新增一个与其对应的AIDL文件。那么同样按照刚才的步骤右键src文件夹,添加一个名为IHelloMsgInterface的AIDL文件。
// IHelloMsgInterface.aidl package com.example.aidltest; parcelable HelloMsg;
注意到
parcelable的首字母是小写的,这算是AIDL一个特殊的地方。
接下来还需要修改IMyAidlInterface.aidl文件,如下:
// IMyAidlInterface.aidl package com.example.aidltest; import com.example.aidltest.HelloMsg; interface IMyAidlInterface { HelloMsg sayHello(); }
即便
IMyAidlInterface.aidl和IHelloMsgInterface
.aidl位于同一个包下,这里的
import是必须要有的。这也是AIDL一个特殊的地方。
注意:build之后发现会报错,将IHelloMsgInterfece.aidl重命名为HelloMsg.aidl即可。
build成功之后会在build/generated/souce/aidl/debug目录下生成IMyAidlInterface文件。可以大致熟悉下该文件的内容,对掌握android binder机制很有帮助
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.aidltest.IMyAidlInterface { private static final java.lang.String DESCRIPTOR = "com.example.aidltest.IMyAidlInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.aidltest.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.example.aidltest.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.aidltest.IMyAidlInterface))) { return ((com.example.aidltest.IMyAidlInterface)iin); } return new com.example.aidltest.IMyAidlInterface.Stub.Proxy(obj); }
这里有个内部类Stub,它继承系统Binder类和实现IMyAidlInterface接口。另外还提供了asInterface()接口,这个方法接受一个远端
Binder对象,并将其转化成
Stub对应的接口对象并返回。在构造方法调用Binder中的attachInterface方法把当前服务对象和描述符进行关联。在asInterface方法中会调用queryLocalInterface查询,如果不在同一进程就返回null,这个时候就返回Proxy对象。
上面看完了Stub类之后,发现他其实是远端服务Binder对象的一个中间者,用来和客户端进行交互的,下面再来看一下Proxy类:
private static class Proxy implements com.example.aidltest.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 com.example.aidltest.HelloMsg sayHello() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); com.example.aidltest.HelloMsg _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_sayHello, _data, _reply, 0); _reply.readException(); if ((0!=_reply.readInt())) { _result = com.example.aidltest.HelloMsg.CREATOR.createFromParcel(_reply); }
可以看到里面有个mRemote对象,它是服务端传递过来的binder对象。调用transact方法后会调用上面Stub中的onTransact方法。这里其实用了静态代理模式,Proxy就是远端传递过来的binder的本地代理。可以理解为客户端的中间者。
Stub类是服务端的中间者,一般是实现了AIDL接口类型和继承了Binder类,具备将Binder对象转化成原生对象的能力
Proxy类是客户端的中间者,一般是实现了AIDL接口类型
下面实现服务端的接口,定义RemoteService.java
public class RemoteService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return new IMyAidlInterface.Stub() { @Override public HelloMsg sayHello() throws RemoteException { return new HelloMsg("wuliqing", 28); } }; } }
客户端调用服务端接口代码如下:
public class MainActivity extends AppCompatActivity { private IMyAidlInterface iMyAidlInterface = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onStart() { super.onStart(); Intent intent = new Intent(this, RemoteService.class); bindService(intent, serviceConnection, BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(serviceConnection); } private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { iMyAidlInterface = null; } }; public void onClickToSayHello(View view) { if (iMyAidlInterface != null) { try { HelloMsg helloMsg = iMyAidlInterface.sayHello(); Toast.makeText(this, helloMsg.toString(), Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); Toast.makeText(this, e.toString(), Toast.LENGTH_SHORT).show(); } } } }
在
onServiceConnected()回调中,我们使用
IMyAidlInterface.Stub.asInterface(service)方法返回我们的接口的引用。接着客户端就可以通过它来对服务端发送请求了。
在这里我为RemoteService设置了process属性,让它运行在与默认进程不同的进程中。
<service android:name="RemoteService" android:process=":remote" />
从上图可看出客户端和服务运行在两个进程当中。
然后点击按钮,成功返回结果。
最后给出一张流程图,加深印象:
关于AIDL和binder机制可参考下面文章:
Android中AIDL的基本用法
Binder机制和远程服务调用机制分析
相关文章推荐
- AIDL简单使用Demo
- 一个简单的demo学习Android远程Service(AIDL的使用
- AIDL的简单使用
- android AIDL的简单使用
- IPC 主要是messenger和aidl的使用和简单分析
- AIDL通信机制简单使用步骤
- 一个简单的demo学习Android远程Service(AIDL的使用)
- aidl简单的使用步骤
- 使用AIDL实现IPC通信之——简单调用远程服务的方法
- AIDL的简单使用
- aidl 的简单介绍和使用
- AIDL简单使用
- android中aidl的简单使用
- Android进程间通信-AIDL的简单使用
- AIDL简单使用(通过它跨应用传递对象(数据))
- 安卓AIDL的简单使用 (复杂情况下,在此基础扩展)
- AIDL简单使用
- aidl的简单使用
- 简单理解IPC机制和AIDL的使用
- Android aidl简单使用