【Android IPC】AIDl使用详解

感觉安卓的ipc还有有些门槛的,初学时无非是看网上的文章或者看开发艺术那本书上的demo。看书上的demo时作者直接就使用了’‘实现Parcelable接口的数据类型’’,非基本数据类型,初学时老是遇坑。网上的文章点赞多的好多也是仿写作者的demo。其他的文章可能写的不够系统,这就造成自己比着demo写老是出现bug,最终放弃了。。。经历过这种感受后,自己就决定趁着这次温习知识的过程来详细的总结下aidl写法。达到知新的效果,同时帮助大家快速入门这块进阶知识!!!!

一、基础

1、概念

aidl:android interface definition language即安卓接口定义语言,安卓ipc方式之一。

2、为啥设计这种语言

为了跨进程通信啊,这门语言就像一个桥梁吧两个app,确切的说应该是吧两个进程联系起来,使他们可以进行交流通信。

3、aidl语法

语法十分简单,和java几乎一样。

(1)文件后缀

我们平时写的代码文件为.java而aidl文件为.aidl文件和java文件一样studio/idea提供快速创建方式。

(2)支持数据的类型

  • java的基本数据类型:byte,short,int,long,float,double,boolean,char
  • String 类型。
  • CharSequence类型
  • List只支持ArrayList,list中的元素类型必须是aidl支持类型。
  • Map只支持HashMap,map中的元素类型必须是aidl支持类型,包括key value。
  • Parcelable:所有实现了Parcelable接口的类(具体使用参考下栗子)
  • aidl接口本身:所有的aidl接口本身也可以在aidl文件中使用。

二、栗子:使用基本数据类型、不同app之间进行aidl

1、基本数据类型是常见的数据类型,使用起来坑少的多,并且service基础文章《Android四大组件—Service》通过bindService方式开启的栗子也实践过,这里在之前的栗子上改写平滑深入更易使大家接受。
2、由于app的四大组件一般默认运行在主进程,所以两个app就是两个不同的进程啦!两个app之间传递一句信息就是简单的通信啦。
基于这两点分析我们就来个栗子:

1、回顾MusicService

使用aidl进行ipc时,工程的文件夹、很重要,这里就特别回顾下之前bindService方式栗子的包名文件夹。

在这里插入图片描述

2、换汤不换药操作:修改之前的接口MusicManager

1、其实安卓的组件和service通信模型就是C/S模型。比如《Android四大组件—Service》中activity中通过bindService方式开启MusicService,然后通过MusicManager接口调用方法和MusicService通信。我们可以理解为activity就是客户端,MusicService就是服务端。
2、使用aidl方式进行ipc时服务端我们还使用这个MusicService,但是MusicManager.java文件要变成MusicManager.aidl文件(具体操作如下图)
3、为啥变MusicManager.aidl???因为如果客户端还是使用MusicManager。这个类假如是MusicManager.java接口的话,我们如何在另一个app中使用它?根本没法使用?所以这里使用MusicManager.aidl,因为安卓系统使用bind对aidl进行了封装。另一个app中移植下aidl文件后两app就可以进行ipc了。

(1)通过编译器创建aidl文件

手动创建也行,只是下图生成的aidl文件夹、子文件夹(包名)、aidl文件都要我们手动创建,然后rebuild project。

在这里插入图片描述
在这里插入图片描述

如上图神奇的事情发生了,编译器自动帮我们在main文件夹下建立个aidl文件,然后创建同包名的文件夹(com.sunnyday.administrator.servicedemo.services)在这个文件夹下创建了个aidl文件
ps:可能会遇到如下坑,原因分析可能是gradle的buildToolsVersion "29.0.2"版本不兼容,吧这句删除即可。亲测屡试不爽。

com.android.ide.common.workers.WorkerExecutorException: 
1 exception was raised by workers:
 java.lang.RuntimeException:
 java.lang.RuntimeException:
 java.io.IOException:
 com.android.ide.common.process.ProcessException:
 Error while executing process 
 D:\androidevn\sdk\build-tools\29.0.0\aidl.exe with arguments 
 {-pD:\androidevn\sdk\platforms\android-29\framework.aidl 
 -oE:\AsProjects\servicedemo\app\build\generated\aidl_source_output_dir\debug\compileDebugAidl\out 
 -IE:\AsProjects\servicedemo\app\src\debug\aidl -IE:\AsProjects\MY\app\src\main\aidl 
 -IC:\Users\zb\.gradle\wrapper\dists\gradle-4.4-all\caches\transforms-2\files-2.1\4b6854fbce58e1d04f4d14eeade6ab12\aidl 
 -IC:\Users\zb\.gradle\wrapper\dists\gradle-4.4-all\caches\transforms-2\files-2.1\3702cc676a28c3d70a3a170f6be0425e\aidl 
 -dC:\Users\zb\AppData\Local\Temp\aidl4795291112600340041.d E:\AsProjects\servicedemo\app\src\main\aidl\com\example\mytest\PlayManager.aidl}

(2)简单修改MusicManager.aidl文件

删除无用代码,添加方法。rebuild project

在这里插入图片描述

(3)修改MusicService

之前的接口不用啦,换成了aidl文件,MusicService内的MyBind类实现接口肯定会报错啦!!!这里也要修改啦!!!

在这里插入图片描述

可以看到,其实也就是让MyBind类继承了MusicManager.Stub类。其实Stub是系统帮我们生成的MusicManager的内部类。这里我们无需多管直接这样继承即可。

(4)服务端完工#运行app

至此,服务端就完工啦!我们只需运行app,等待其他的进程开启这个服务即可。

3、新建客户端app

新建个工程,我这里取名为ClientDemo

(1)代码

public class MainActivity extends AppCompatActivity {
    MusicManager musicManager;
    private ServiceConnection conn;
    private Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

         //隐式启动
        intent = new Intent();
        intent.setAction("com.sunnyday.administrator.servicedemo.services.MusicService");
        intent.setPackage("com.sunnyday.administrator.servicedemo");

        conn = new MyServiceConnection();
    }

    // 绑定按钮
    public void bindRemoteService(View view) {
        bindService(intent, conn, BIND_AUTO_CREATE);
    }

     // 播放按钮
    public void PlayMusic(View view) {

        try {
            if (null != musicManager) {
                Log.i("233", "test: ");
                musicManager.playMusic();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private class MyServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 获得实例
            musicManager = MusicManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}

如上开启方式很简单,隐式开启。我们先点击绑定按钮,再点击播放按钮log如下。

在这里插入图片描述
(2)注意点

1、Service android:exported=“true”,否则绑定失败
2、这里除了设置action之外还要设置下包名否则会报错( Service Intent must be explicit: Intent { act=com.example.mytest.MyService } 必须使用显示intent)

三、Aidl中使用非默认支持数据类型注意点

aidl 文件默认支持了常见的数据类型,如果我们想在aidl文件中使用自定义对象这时我们需要注意如下:
1、自定义对象实现序列化接口
2、自定义对象在aidl中导包

栗子:类Book实现了paecelable接口,BookManager.aidl文件要使用Book类。这时我们需要另外创建Book.aidl文件然后在BookManager.aidl文件中paecelable关键字声明Book。这时BookManager.aidl才能使用Book类.

在这里插入图片描述#bookmanager.aidl

在这里插入图片描述

如上在红线1出new的aidl文件,系统在main目录下帮我们建立了同包名的目录。然后建立aidl文件。这时我们直接使用Book类,然后build一下报错:

在这里插入图片描述

解决#建立Book同包名,同类名的Book.aidl

在这里插入图片描述

在这里插入图片描述

不是同类名吗?此处我们先写Bookl写Book会报错。我们先写Bookl生成aidl文件我们在refactor即可。

在这里插入图片描述

删除 interface 在使用parcelable 定义下Book类。

在这里插入图片描述

显式导包就可以使用了,build也不会报错了。

The end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值