Android Aidl 的使用

Binder框架 – android AIDL 的使用

Binder框架 – 用户空间和驱动的交互

Binder框架 – Binder 驱动

Binder 框架 – binder 用户空间框架

Aidl 是android 跨进程通信的中一种,是一种RPC。底层基于binder 框架。通常用在C/S架构中。

Aidl 跨进程通信支持有限的数据类型

Aidl 可以进行跨进程通信,但是不是所有的数据类型都支持,支持的类型主要是:

  1. Java 的基本类型
  2. String 和CharSequence
  3. List 和 Map, 并且List和Map 对象的元素必须是AIDL支持的数据类型;以上三种类型都不需要导入(import)
  4. AIDL 自动生成的接口 需要导入(import)
  5. 实现android.os.Parcelable 接口的类. 需要导入(import)。

创建Aidl 文件

在android studio 中直接new 一个Aidl 文件 IHelloWorldInterface.aidl。注意文件命名规则,IXXX.adil。 只定义了一个printHelloWorld 接口。

interface IHelloWorldInterface {    /**     * 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);    String printHelloWorld();}

编译后生成 IHelloWorldInterface.java 文件。由于文件是aidl 工具生成的,格式比较乱,代码用工具格式化后IHelloWorldInterface 是一个接口,里面主要是两个类静态虚类public Stub类和private Stub.Proxy 类,Stub为存根的意思,那就是服务端使用,Stub.Proxy 为代理类,客户端使用。

public interface IHelloWorldInterface extends android.os.IInterface {    public static abstract class Stub extends android.os.Binder implements com.example.louiewh.aidlapplication.IHelloWorldInterface {        private static final java.lang.String DESCRIPTOR = "com.example.louiewh.aidlapplication.IHelloWorldInterface";        private static class Proxy implements com.example.louiewh.aidlapplication.IHelloWorldInterface {            private android.os.IBinder mRemote;            @Override            public java.lang.String printHelloWorld() throws android.os.RemoteException {            }        }    }}

服务端的实现

服务端 HelloWorldService 继承 IHelloWorldInterface.Stub 接口

public class HelloWorldService  extends IHelloWorldInterface.Stub {    @Override    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {    }    @Override    public String printHelloWorld() throws android.os.RemoteException {        if(mListerner != null) {            final int begin = mListerner.beginBroadcast();            for (int i = 0; i < begin; i++) {                mListerner.getBroadcastItem(i).onAidlListerner(                        new StringBuilder().                        append("Pid:").append(android.os.Process.myPid()).                        append(" Threadtime:").append(SystemClock.uptimeMillis()).                        toString()                );            }            mListerner.finishBroadcast();        }        return "Hello AIDL!";    }}

创建Service

创建一个AidlService extends Service。AndroidManifext 中注册Service。 在Service 的
onBind 中返回HelloWorldService。

public class AidlService extends Service {    public final static String TAG = "AidlService";    @Override    public void onCreate() {        super.onCreate();    }    @Override    public void onDestroy() {        Log.d(TAG, "onDestroy");        super.onDestroy();    }    @Nullable    @Override    public IBinder onBind(Intent intent) {        return new HelloWorldService();    }}

代理端调用

service 启动

android Service 启动有两种方式,一种startService,一种binderService. 由于我们要获取Service 的代理端,使用binderService。在 MainActivity onCreate 中 binderService。

 Intent intent = new Intent(context, AidlService.class); context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

获取Service Proxy

然后 New 一个ServiceConnection, 在ServiceConnection中的onServiceConnected回调函数中会通过IHelloWorldInterface.Stub.asInterface返回Stub.proxy 对象。这样我们就拿到了服务的代理端。在MainActivity中设置text.setOnClickListener,当点击时显示printHelloWorld 的结果,就是进程PID和uptimeMillis时间。

ServiceConnection helloWorldConn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            remoteService = IHelloWorldInterface.Stub.asInterface(iBinder);         }        @Override        public void onServiceDisconnected(ComponentName componentName) {        }    };text.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                try {                    text.setText(remoteService.printHelloWorld());                } catch (RemoteException e) {                    e.printStackTrace();                }            } });

service 退出

在Activity退出时,需要unbinder

protected void onDestroy() {     helloWorldProxy.unbindService();     super.onDestroy();}

一个Aidl 通信的架构就基本完完成了.

需要注意的是ServiceConnection是异步通信

设置listener

现在客户端可以调用服务端了,如果服务端需要通知客户端呢,就需要listener 出场了,listener 同样基于Aidl。定义一个onAidlListerner 回调。

1. 定义IAidlListernerInterface

interface IAidlListernerInterface {    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,            double aDouble, String aString);    void onAidlListerner(String str);}

2. 定义一个抽象类 AidlListerner 继承IAidlListernerInterface.Stub。


public abstract class AidlListerner extends IAidlListernerInterface.Stub {
}

3. IHelloWorldInterface.aidl 中增加两个函数,注册listener 和 反注册listener。

 void registerListerner(IAidlListernerInterface listener); void unregisterListerner(IAidlListernerInterface listener);

4. HelloWorldService 中同样实现这两个函数。

同时有一个变量 ArrayList\

 public String printHelloWorld() throws RemoteException {        if(mListerner != null) {            for (int i = 0; i < mListerner.size(); i++) {                mListerner.get(i).onAidlListerner(new StringBuilder().append("current time:").append(SystemClock.currentThreadTimeMillis()).toString());;            }        }        return "Hello AIDL!";    }

5. MainActivity 中 注册

这样在点击text 的时候 listenertext 会显示printHelloWorld 的结果。

remoteService.registerListener(new AidlListener() {            @Override            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {            }            @Override            public void onAidlListerner(String str) throws RemoteException {                listenerText.setText(str);            }        });        

onDestory 中 unregisterListener。

6. 多进程模式下RemoteCallbackList

现在Service 和Activity 运行在一个进程中,Service 和 Client 通常运行在不同的进程中,现在我们配置Service 运行在另外一个进程。 这时候需要注意的是在HelloWorldService 中保存listener 的变量mListerner 类型为ArrayList 修改为: RemoteCallbackList\ mListerner = new RemoteCallbackList\();
原因是因为垮进程的listener 的指针地址改变了。listener 的遍历方式也发生了变化。

 <service     android:name=".AidlService"     android:process=":AidlService"> service>  
if(mListerner != null) {     final int begin = mListerner.beginBroadcast();     for (int i = 0; i < begin; i++) {         mListerner.getBroadcastItem(i).onAidlListerner(new StringBuilder().                     append("Pid:").append(android.os.Process.myPid()).                      append("Current time:").append(SystemClock.currentThreadTimeMillis()).                        toString()        );    }    mListerner.finishBroadcast();}

代理服务

在一个应用里可能有很多这样的Aidl 文件,通常的做法是每个Aidl 文件都都建一个Service 用来bind,这样一个APK 进程中有很多Service 存在。是不是我们用一个Service 就可以了,因为都是在后台运行,这样就大大减小了对内存的消耗。在讲到Aidl 传输数据类型的时候Aidl 本身也支持Aidl自动生成的Interface 类型的传输,而我们定义的业务Service,比如HelloWorldService 本身就是继承Aidl 自动生成的Interface 类型。所以可以有一个专业的Service 来传递业务Service。 通常在获取系统服务的时候是 getApplicationContext().getSystemService(“XXX”), 同样也定义一个这样的API,来为应用内的调用提供APK 级别的Service 服务。

定义 IAidlBinderService.aidl

这个Aidl 文件之定义一个接口getService.

interface IAidlBinderService {    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,            double aDouble, String aString);    IBinder getService(String service);}

所有的业务Service 都通过getService 获取。

AidlBinderService 的服务端

onBind 的时候返回AidlBinderService 的Binder。
通过getService 传递进来的参数返回不同的Service 服务。这里一共两种业务Service,HelloWorldService HelloAidlService。这两种Service 单独一个java 文件,和Service 代码分离,当加入一个新的Service的时候,通常定义Aidl 文件,Service 代码继承 Stub 接口。然后定义getService 的字符串就可以加入一个新的Service。

public class AidlService extends Service {    public final static String HELLOWORLDSERVICE = "HelloWorldService";    public final static String HELLOAIDLSERVICE = "HelloAidlService";    public final static String TAG = "AidlService";    @Override    public void onCreate() {        super.onCreate();    }    @Override    public void onDestroy() {        Log.d(TAG, "onDestroy");        super.onDestroy();    }    @Nullable    @Override    public IBinder onBind(Intent intent) {        return new AidlBinderService();    }    class AidlBinderService extends IAidlBinderService.Stub{        @Override        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {        }        @Override        public IBinder getService(String service) throws RemoteException {            switch(service) {                case HELLOWORLDSERVICE:                    return new HelloWorldService();                case HELLOAIDLSERVICE:                    return new HelloAidlService();                default:                    return null;            }        }    }}

AidlBinderService 的代理。

在处理AidlBinderService 的代理的时候,通常是在 ServiceConnection 回调中得到 iBinder。 这是一个异步的通信。我们希望代码能够耦合度更低,和业务能够分开,把AidlBinderService 单独的实现子啊一个java 文件中。一个做法是使用异步转同步的方法,直到ServiceConnection 的 onConnected 返回。但是这样毕竟有系统时间的消耗,而Service 的binder通常在APK 启动时,影响启动速度。这里继续沿用异步回到,两种方法,设置回调函数,使用Handler。AidlBinderServiceProxy 为单例模式,构造函数中去bindService,在onServiceConnected 使用传递进来的Handler 发送binderService 成功的消息。

获取AidlBinderService 的代理

public class AidlBinderServiceProxy {    static final String TAG = "AidlBinderServiceProxy";    static final int AidlBinderService = 1;    private Context mContext;    private ServiceConnection mConnection;    private IAidlBinderService mRemoteService;    private Handler mHandler;    private static AidlBinderServiceProxy instance;    private AidlBinderServiceProxy(Context context, Handler handler) {        mContext = context;        mHandler = handler;        initServiceConnection();        Intent intent = new Intent(context, AidlService.class);        context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);    }    public static AidlBinderServiceProxy instance(Context context, Handler handler){        synchronized (AidlBinderServiceProxy.class) {            if(instance == null) {                instance = new AidlBinderServiceProxy(context, handler);            }        }        return instance;    }    public void unbindService() {        Log.d(TAG, "unbindService");        mContext.unbindService(mConnection);        instance = null;    }    private void initServiceConnection() {        mConnection = new ServiceConnection() {            @Override            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {                mRemoteService = IAidlBinderService.Stub.asInterface(iBinder);                Message message = Message.obtain(mHandler, AidlBinderService);                mHandler.sendMessage(message);                Log.d(TAG, "onServiceConnected");            }            @Override            public void onServiceDisconnected(ComponentName componentName) {            }        };    }    public IBinder getService(String service) {        if(mRemoteService == null) {        }        try {            return mRemoteService.getService(service);        } catch (RemoteException e) {            Log.e(TAG, "getService " + "service");            e.printStackTrace();        }        return null;    }}

实现业务Service 的Proxy

实现两个业务Service 的Proxy。HelloAidlProxy 如下,在构造函数中通过getService 获取到IBinder 对象,通过I HelloAidlInterface.Stub.asInterface 函数转为代理对象。

public class HelloAidlProxy {    static final String TAG = "HelloAidlProxy";    public AidlBinderServiceProxy  mAidlBinderService;    private IHelloAidlInterface mRemoteService;    public HelloAidlProxy(AidlBinderServiceProxy proxy) {        mAidlBinderService = proxy;        IBinder binder = mAidlBinderService.getService(AidlService.HELLOAIDLSERVICE);        mRemoteService = IHelloAidlInterface.Stub.asInterface(binder);    }    public PidInfo getPidInfo() {        if(mRemoteService != null){            try {                return mRemoteService.getPidInfo();            } catch (RemoteException e) {                e.printStackTrace();            }        }        return null;    }}

调用

修改MainActivity 的实现, 实现一个内部Handler 类:

class AidlHandler extends Handler{    public void handleMessage(Message msg) {        switch(msg.what) {            case AidlBinderServiceProxy.AidlBinderService:                Log.d("louie", "AidlBinderService");                helloWorldProxy = new HelloWorldProxy(mAidlBinderService);            default:                break;            }        });            

使用代理服务前后App 的结构变化:


https://www.processon.com/view/link/57a5991be4b02c28bf471316

Parcelable

上面已经实现了Aidl 生成的类型的数据跨进程传递,Aidl 生成的数据类型主要用于C/S 这样的架构。对于普通的对象如何处理呢,android 给我们准备了Parcelable 这种数据类型。和java 的Serializable 比较类似,Serializable 序列化基于文本,Parcelable 基于binder,效率更高。Parcelable 基于android提供的Parcel类型,将数据写入Parcel打包,需要的时候再从Parcel 读出完成序列化。

定义类继承 Parcelable

类 PidInfo implements Parcelable

  • 重写writeToParcel方法,将对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel中
  • 重写describeContents方法,内容接口描述,默认返回0就可以
  • 实例化静态内部对象CREATOR实现接口Parcelable.Creator,在 createFromParcel new 了一个参数为 Parcel 构造函数,需要注意的是:
    这个构造函数实现的时候的读写顺序要和writeToParcel 方法一致
public class PidInfo implements Parcelable {    private int mPid;    PidInfo(int pid ){        mPid = pid;    }    PidInfo(Parcel in ) {        mPid = in.readInt();    }    public int getPid(){        return mPid;    }    public void setPid(int pid ){        mPid = pid;    }    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {         dest.writeInt(mPid);    }    public static final Creator CREATOR = new Creator(){        @Override        public PidInfo createFromParcel(Parcel source) {            return new PidInfo(source);        }        @Override        public PidInfo[] newArray(int size) {            return new PidInfo[0];        }    };}

AIDL 声明

PidInfo 定义完后还不能直接使用,需要在Aidl 中声明:

  • 新建一个和类同名的Aidl 文件 PidInfo.aidl
  • 在PidInfo.aidl 中 声明PidInfo 为parcelable 类型
parcelable PidInfo;

code

Aild 的使用大概就是这些,code 地址:github

更多相关文章

  1. C语言函数的递归(上)
  2. Android(安卓)NDK学习笔记4-Android.mk篇
  3. Android使用addView动态添加组件
  4. Android输入系统(三):加载按键映射
  5. [置顶] Android(安卓)Gallery用法(自定义边框+底部小圆点)
  6. Android那些事儿之自定义进度条
  7. Android向服务器的数据库MySQL传输数据:经过修正的 Android(安卓)
  8. Android的NDK开发(5)————Android(安卓)JNI层实现文件的read
  9. Android(安卓)编译,打包、签程名详细教

随机推荐

  1. android Tab和ViewPager结合的例子
  2. Android(安卓)view点击放大缩小
  3. android in practice_Using standard Con
  4. Android(安卓)创建文件的工具类
  5. Android开发之环形进度条(安卓默认…
  6. android,webview增加自定义JS对象,调用过
  7. Android(安卓)Studio:Could not find clas
  8. 查看android內存等使用情況
  9. DatePickerDialog的使用
  10. android ListView详解(持续中。。。)