AIDL 安卓进程间通信/跨应用通信
来源:互联网 发布:图像 meanshift算法 编辑:程序博客网 时间:2024/06/06 00:54
前言
最近出去面试找工作,被人问到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.aidlpackage com.kikt.aidl;// Declare any non-default types here with import statementsinterface 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 statementspublic 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.aidlpackage com.kikt.aidl;// Declare any non-default types here with import statementsinterface 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知识的海洋中不可自拔的博主
- AIDL 安卓进程间通信/跨应用通信
- 安卓IPC(进程间通信)之AIDL基本使用
- 安卓学习 AIDL跨应用Service绑定与通信
- AIDL实现应用进程间的通信。
- AIDL 进程间通信
- AIDL 进程间通信
- AIDL 进程间通信
- AIDL 进程间通信
- AIDL进程间通信
- AIDL:进程间通信
- AIDL进程间通信
- AIDL 进程间通信
- aidl 进程间通信
- AIDL进程间通信
- 进程间通信---AIDL
- AIDL进程间通信
- AIDL进程间通信
- 安卓aidl夸进程通信的小例子,
- LeetCode09:Palindrome Number
- 工具链接
- spring mvc 使用kaptcha生成验证码
- Odd Even Linked List
- Python caffe cuda7.5 windows pycharm
- AIDL 安卓进程间通信/跨应用通信
- 漫步凸分析八——回收锥与无界
- 前端收藏
- 写在博客开通之初
- 关于内存泄露的总结
- ftp创建文件权限问题
- android Studio基本配置
- windows下python安装Numpy、Scipy、matplotlib模块
- window 下杀死占用端口进程