前言
最近出去面试找工作,被人问到AIDL,我就回答这个东西我用过,也大概理解,Android的进程间通信语言嘛,人家不置可否,那我能咋着呢,毕竟没深入研究过,也没办法,咱只能回来奋发图强了
写在前面
我以前就看过的一个博客,里面原理代码什么都有,写的水平肯定比我高
Android开发者指南(6) —— AIDL
首先字面解释
A=Android
IDL=Interface definition language
意译就是android接口定义语言,马丹,完全看不明白
算了,就是Android官方给我们定义出来跨进程,甚至跨应用通信用的
开发平台
Android Studio 2.2+Android手机一部
新建工程
这个就不说了,跳过
就是新建工程后再建一个module 也是android app,功能后面再说
aidl语法
这里请去看我写在前面,里面比较详细,或者自行baidu/google,我也了解的不多
代码示例
最关键的地方到了
其实就是新建一个aidl文件
// IMyAidlInterface.aidl
package com.kikt.aidl;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
void test(int sum,int sum2);
}
接着make project,生成下java代码
找到生成的代码看下
我靠 好复杂,还是渣格式,这里格式化一下:
不想看完全代码的可以看下后面的结构图
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: H:\\Git\\ASWorkSpace\\public\\AidlDemo\\app\\src\\main\\aidl\\com\\kikt\\aidl\\IMyAidlInterface.aidl
*/
package com.kikt.aidl;
// 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.kikt.aidl.IMyAidlInterface {
private static final java.lang.String DESCRIPTOR = "com.kikt.aidl.IMyAidlInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.kikt.aidl.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.kikt.aidl.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.kikt.aidl.IMyAidlInterface))) {
return ((com.kikt.aidl.IMyAidlInterface) iin);
}
return new com.kikt.aidl.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_test: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
this.test(_arg0, _arg1);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.kikt.aidl.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;
}
@Override
public void test(int sum, int sum2) 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(sum);
_data.writeInt(sum2);
mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_test = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void test(int sum, int sum2) throws android.os.RemoteException;
}
这里生成了一个静态内部类Stub
方法签名如下
public static abstract class Stub extends android.os.Binder implements com.kikt.aidl.IMyAidlInterface
这个类是抽象类 这里类本身实现了对应的接口IMyAidlInterface,但没有实现我们在aidl中定义的方法test(int,int)方法
这也代表了test方法需要我们自己来实现
另外方法继承了android.os.Binder,看到这个的时候,我们就知道,这个应该用在什么地方了
对了,和Service必须实现的那个接口onBind的返回参数一样!
这里写个类继承下
package com.kikt.aidldemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.kikt.aidl.IMyAidlInterface;
public class MyService extends Service {
private static final String TAG = "MyService";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return new AidlEntity();
}
public class AidlEntity extends IMyAidlInterface.Stub{
@Override
public void test(int sum, int sum2) throws RemoteException {
Log.d(TAG, "test() called with: sum = [" + sum + "], sum2 = [" + sum2 + "]");
}
}
}
为了方便,直接写在service内部
这里只是简单的做一个日志输出,其他什么也没有干
同应用调用
这里是同应用调用
直接看核心代码
bindService(new Intent(this, MyService.class), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IMyAidlInterface test = IMyAidlInterface.Stub.asInterface(service);
try {
test.test(1, 2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
这里就是一个按钮点击后bindService,然后connection会接受到一个IBinder的实例,这个实例就是上面service的那个
当然还有一个写法,直接强转也不会报错
bindService(new Intent(this, MyService.class), new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// IMyAidlInterface test = IMyAidlInterface.Stub.asInterface(service);
// try {
// test.test(1, 2);
// } catch (RemoteException e) {
// e.printStackTrace();
// }
MyService.AidlEntity service1 = (MyService.AidlEntity) service;
try {
service1.test(4,5);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
效果都是一样的,那么这个什么aidl还有个毛用啊,强转就好了
接着就是高潮了
跨应用调用
没错,我个人认为最重要的也就是这点了,aidl可以在不同应用中调用
比如我要做一个提供服务的应用,或者说是同公司的核心组件,而不希望别人知道我的具体实现
这时我直接丢给你我的aidl文件,告诉你包名和服务名称,你就去调就好了!
ComponentName componentName = new ComponentName(
"com.kikt.aidldemo", "com.kikt.aidldemo.MyService");
Intent intent = new Intent();
intent.setComponent(componentName);
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IMyAidlInterface iinterface = IMyAidlInterface.Stub.asInterface(service);
try {
iinterface.test(10, 20);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
这里和上面的代码看上去差不多,但是我和原来的不是一个应用,而是第二个应用
这里使用test方法时,可以看到提供服务的应用可以输出日志
而引申下
如果这里有一个算法,实现了两个参数间的计算,那么我们是不是可以得到计算结果呢,比如说一个加密方法,我不需要知道具体实现,只要调用就好了
aidl修改如下:
// IMyAidlInterface.aidl
package com.kikt.aidl;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
void test(int sum,int sum2);
int add(int num,int num2);
}
内部类实现修改
public class AidlEntity extends IMyAidlInterface.Stub{
@Override
public void test(int sum, int sum2) throws RemoteException {
Log.d(TAG, "test() called with: sum = [" + sum + "], sum2 = [" + sum2 + "]");
}
@Override
public int add(int num, int num2) throws RemoteException {
return num + num2;
}
}
调用者应用的bindService中修改如下:
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IMyAidlInterface iinterface = IMyAidlInterface.Stub.asInterface(service);
try {
iinterface.test(10, 20);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
int add = iinterface.add(1, 2);
Log.d("MainActivity", "add:" + add);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
在第二个中点击可以看到日志输出
思维发散
其实aidl就像一个核心,模块化开发的时候,核心模块不用给你代码,只要你去aidl文件,和跨应用的调用方法即可,而你实现后续的业务逻辑,也算是一种解耦的方式吧
高级/原理
再回到Stub的实现中,看下onTransact方法就可以看出,其实aidl是实现自android提供的序列化
通过约定的方式,将方法名的参数和返回值序列化后再通过约定的方式取出来,这样来实现进程间通信
当然具体的内部原理因为我对于framework层没有深入研究,传输的过程我不太了解
@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_test: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
this.test(_arg0, _arg1);
reply.writeNoException();
return true;
}
case TRANSACTION_add: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
后记
其实aidl很方便也是一种跨应用的解决方案,非常实用,面试和工作中都应该用得到,后续如果有机会可以多使用下,就先写这么多吧,谢谢网上的android先驱者和大神们!!!
遨游在android知识的海洋中不可自拔的博主