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方式栗子的包名文件夹。

Android IPC-AIDl使用详解_第1张图片

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。

Android IPC-AIDl使用详解_第2张图片
Android IPC-AIDl使用详解_第3张图片

如上图神奇的事情发生了,编译器自动帮我们在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

Android IPC-AIDl使用详解_第4张图片

(3)修改MusicService

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

Android IPC-AIDl使用详解_第5张图片

可以看到,其实也就是让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如下。

Android IPC-AIDl使用详解_第6张图片
(2)注意点

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

三、栗子:使用基本数据类型、同app内不同进程进行aidl

待续!!!


以下待整理:aidl文件分类

  • type one:定义parcelable对象,以供其他AIDL文件使用AIDL中非默认支持的数据类型
  • type two:定义方法接口,以供系统使用来完成跨进程通信。(如下的Bookmanager.aidl)

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

由于自己踩过坑,所以就下面附录了详细使用aidl截图。(以便我们入门aidl脱坑哈)
Android IPC-AIDl使用详解_第7张图片

如上创建bookmanager.aidl 结果如下。

Android IPC-AIDl使用详解_第8张图片

如上我们在红线1出new的aidl文件,系统在main目录下帮我们建立了同包名的目录。然后建立aidl文件。

这时我们直接使用Book类,然后build一下报错:
Android IPC-AIDl使用详解_第9张图片

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

Android IPC-AIDl使用详解_第10张图片

Android IPC-AIDl使用详解_第11张图片

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

重要步骤:
Android IPC-AIDl使用详解_第12张图片

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

Android IPC-AIDl使用详解_第13张图片

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

具体实践

1、梳理下service的通信过程

aidl也是分服务端,客户端。和service的使用类似,这里我们就再梳理下service的通信流程。

Android IPC-AIDl使用详解_第14张图片

其实aidl用法和service类似。

2、aidl 简单实践

详细参考:
1、https://blog.csdn.net/luoyanglizi/article/details/51980630
2、https://www.cnblogs.com/zhujiabin/p/6080827.html
3、安卓开发艺术 第二章

The end

你可能感兴趣的