Android 中的AIDL

899 阅读3分钟

aidl是android中跨进程通信的一种方式。一般有两种实现,第一种是一个应用里面有两个进程,第二种是两个应用间的通信。同一应用的多进程通信可以参考这篇文章;不同应用的跨进程实现可以参考这篇文章这篇文章

当我们运用aidl的时候,系统会自动为我们生产对应的java类,通过分析这个类可以明白Binder的运行机制,具体的可以参考这篇文章里面的关于aidl的理解,或者安卓开发艺术探索这本书。为了加深理解,可以参考下面的图片。

Binder的工作机制

具体的代码实现可以参考这个demo

另外,aidl的方式是系统为我们自动生成代码,方便我们实现进程间通信,也可以不通过aidl自己写binder实现进程间通信。 从上述分析过程来看,我们完全可以不提供AIDL文件即可实现Binder,之所以提供AIDL文件,是为了方便系统为我们生成代码。系统根据AIDL文件生成Java文件的格式是固定的,我们可以抛开AIDL文件直接写一个Binder出来,接下来我们就介绍如何手动写一个Binder。还是上面的例子,但是这次我们不提供AIDL文件。参考上面系统自动生成的IBookManager.java这个类的代码,可以发现这个类是相当有规律的,根据它的特点,我们完全可以自己写一个和它一模一样的类出来,然后这个不借助AIDL文件的Binder就完成了。但是我们发现系统生成的类看起来结构不清晰,我们想试着对它进行结构上的调整,可以发现这个类主要由两部分组成,首先它本身是一个Binder的接口(继承了IInterface),其次它的内部由个Stub类,这个类就是个Binder。

根据上面的思想,手动实现一个Binder可以通过如下步骤来完成:(1)声明一个AIDL性质的接口,只需要继承IInterface接口即可,IInterface接口中只有一个asBinder方法,并声明要调用的方法;(2)实现Stub类和Stub类中的Proxy代理类,这段代码我们可以自己写,但是写出来后会发现和系统自动生成的代码是一样的,因此这个Stub类我们只需要参考系统生成的代码即可。

具体的参考这个demo

接下来,我们介绍Binder的两个很重要的方法linkToDeathunlinkToDeath。我们知道,Binder运行在服务端进程,如果服务端进程由于某种原因异常终止,这个时候我们到服务端的Binder连接断裂(称之为Binder死亡),会导致我们的远程调用失败。为了解决这个问题,Binder中提供了两个配对的方法linkToDeath和unlinkToDeath,通过linkToDeath我们可以给Binder设置一个死亡代理,当Binder死亡时,我们就会收到通知,这个时候我们就可以重新发起连接请求从而恢复连接。那么到底如何给Binder设置死亡代理呢?也很简单。首先,声明一个DeathRecipient对象。DeathRecipient是一个接口,其内部只有一个方法binderDied,我们需要实现这个方法,当Binder死亡的时候,系统就会回调binderDied方法,然后我们就可以移出之前绑定的binder代理并重新绑定远程服务:

private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            //binder死亡会回调该方法
            if (bookManager == null) {
                return;
            }
            bookManager.asBinder().unlinkToDeath(deathRecipient, 0);
            bookManager = null;
            //重新绑定远程服务
            bindService(new Intent("com.zzr.aidldemo.RemoteService").setPackage(getPackageName()),
                    serviceConnection, BIND_AUTO_CREATE);
        }
    };
    
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected: 连接成功");
            bookManager = IBookManager.Stub.asInterface(service);
            try {
                //设置死亡代理
                service.linkToDeath(deathRecipient, 0);