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知识的海洋中不可自拔的博主

0 0
原创粉丝点击