最近有一段时间没写博客了,打算最近趁着有时间补补,本文是总结的AIDL的基本使用和原理。
分为两个部分:一是简单的上手demo,二是对代码逻辑进行分析。
一:简单的AIDL小Demo:
服务端:
1.新建服务端工程AIDLserver,新建AIDL文件:
2.打开该文件,编写一个测试方法:
3.点击build-rebuild进行编译,可以看到生成的java类文件,在最后一行可以看到自己刚才写的测试方法input():
4.编写服务端的服务类:
这里要注意一定要返回Ibinder实例。
5.在Manifest里配置该服务,在Activity中启动服务并运行程序:
启动服务
客户端:
1.新建客户端工程AIDLClient,新建一个module工程mylibrary:
2.把之前服务端的aidl文件夹复制到客户端相同位置,并rebuild客户端:
3.在MainActivity中绑定服务端的TESTServer服务,并通过ServiceConnection进行消息回调,在其的onServiceConnected方法中得到IMyAidlInterface的实例。
4.之后创建一个按钮的点击方法,在其中直接调用IMyAidlInterface实例对象发出客户端的信息并直接获得服务端的回调结果。
(3、4完整代码如下):
public class MainActivity
extends AppCompatActivity {
Button
btn_test_aidl
;
@Override
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
;
setContentView(R.layout.
activity_main)
;
btn_test_aidl = (Button) findViewById(R.id.
btn_test_aidl)
;
//绑定服务
Intent intent =
new Intent()
;
intent.setComponent(
new ComponentName(
"com.example.aidlserver"
,
"com.example.aidlserver.MyService"))
;
bindService(intent
,
conn
,
BIND_AUTO_CREATE)
;
btn_test_aidl.setOnClickListener(
new View.OnClickListener() {
@Override
public void
onClick(View view) {
try {
String rep =
iMyAidlInterface.input(
"客户端发出的信息")
;
Log.
i(
"nangua"
,
"从服务端调用成功的结果:" + rep)
;
}
catch (Exception e) {
e.printStackTrace()
;
}
}
})
;
}
IMyAidlInterface
iMyAidlInterface
;
/**
* 服务回调方法
*/
private ServiceConnection
conn =
new ServiceConnection() {
@Override
public void
onServiceConnected(ComponentName name
, IBinder service) {
iMyAidlInterface = IMyAidlInterface.Stub.
asInterface(service)
;
}
@Override
public void
onServiceDisconnected(ComponentName name) {
iMyAidlInterface =
null;
}
}
;
@Override
protected void
onDestroy() {
super.onDestroy()
;
//解绑服务,回收资源
unbindService(
conn)
;
}
}
最后,点击客户端测试按钮,查看双端显示的Log:
二.底层实现原理:
围绕着IMyAidlInterface的代码(方便查找):
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: E:\\Android-workspace\\AIDLsample\\AIDLClient\\app\\src\\main\\aidl\\com\\example\\aidlserver\\IMyAidlInterface.aidl
*/
package com.example.aidlserver;
// 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.aidlserver.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "com.example.aidlserver.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.aidlserver.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.example.aidlserver.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.aidlserver.IMyAidlInterface))) {
return ((com.example.aidlserver.IMyAidlInterface)iin);
}
return new com.example.aidlserver.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_input:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.input(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.aidlserver.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 input(java.lang.String str) 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(str);
mRemote.transact(Stub.TRANSACTION_input, _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_input = (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 input(java.lang.String str) throws android.os.RemoteException;
}
从客户端开始,一步步说:
1.首先在onCreate方法中,绑定了服务端的TestServer服务:
//绑定服务
Log.d("nangua","客户端onCreate中绑定服务");
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.aidlserver", "com.example.aidlserver.TestService"));
bindService(intent, conn, BIND_AUTO_CREATE);
其中我们传入的ServiceConnection为:
/**
* 服务回调方法
*/
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("nangua","客户端回调获得iMyAidlInterface实例");
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
iMyAidlInterface = null;
}
};
在onServiceConnected中,我们调用了IMyAidlInterface实例的Stub内部类的asInterface方法,我们走进该方法:
public static com.example.aidlserver.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.aidlserver.IMyAidlInterface))) {
return ((com.example.aidlserver.IMyAidlInterface)iin);
}
return new com.example.aidlserver.IMyAidlInterface.Stub.Proxy(obj);
}
可以看到最后一行返回结果是调用了Stub内部类的代理内部类Proxy的构造方法,该方法为:
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
可以看到讲传入的远程服务类的IBinder实例保存到了本地,变量名为mRemote(意思是拿到的远程实例).
到此为止,我们可以知道客户端的IMyAidlInterface实例iMyAidlInterface就是该代理类实例mRemote。
然后在我们的点击方法中:
btn_test_aidl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
Log.d("nangua","点击了");
String rep = iMyAidlInterface.input("客户端发出的信息");
Log.d("nangua", "从服务端调用成功的结果:" + rep);
} catch (Exception e) {
e.printStackTrace();
}
}
});
是调用了该实例的input方法,所以现在看到Proxy代理类的input方法:
@Override public java.lang.String input(java.lang.String str) 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(str);
mRemote.transact(Stub.TRANSACTION_input, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
可以看到其中关键的一句:
mRemote.transact(Stub.TRANSACTION_input, _data, _reply, 0);
调用了mRemote实例的transact方法,其中TRANSACTION_input是标志值。
该方法会调用服务端的onTransact方法!
所以此时我们看到服务端IMyAidlInterface实例的代理类Proxy的onTranscat方法:
@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_input:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.input(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
可以看到在case TRANSACTION_input:的情况下,
会得到客户端传来的数据:
java.lang.String _arg0;
_arg0 = data.readString();
然后执行服务端的input方法:
java.lang.String _result = this.input(_arg0);
最后将数据保存:
reply.writeNoException();
reply.writeString(_result);
并返回数据:
return super.onTransact(code, data, reply, flags);
onTransact方法走的是底层代码,通过这个方法的实现,可以将服务端的数据回传给客户端。
此时,客户端的执行方法终于收到了回传的参数:
String rep = iMyAidlInterface.input("客户端发出的信息");
到此,全过程结束。
总结:
可以看到整个数据交互过程,就是客户端通过绑定服务,得到服务端的Aidl实例mRemote,并通过调用该实例的input方法,并在input方法中最终调用进程间通信的底层方法onTransact,实现数据从客户端到服务端,再到客户端的整个回调。过程虽然比较复杂,但是思路是连贯的。