0
点赞
收藏
分享

微信扫一扫

开发AIDL Demo的完整流程(一)

陆佃 2022-04-14 阅读 97

AIDL概述

AIDL是安卓为进程间通讯留下的接口,和其他RPC框架一样,AIDL也包括代理层,协议层和通讯层。代理层是安卓的跨进程通讯机制Binder,协议层是安卓接口定义语言AIDL,代理层除了AIDL自动生成的存根代码之外,还需要手动实现服务的绑定以及服务并将存根转换为服务接口。这就构成了整个AIDL的框架。
具体实现AIDL的过程分为以下几步:

  1. 创建服务端项目,编写AIDL
  2. 注册服务,实现服务方法并回传服务存根
  3. 创建客户端项目,拷贝AIDL
  4. 设计客户端UI
  5. 在客户端实现业务逻辑
  6. 在客户端注册queries
  1. 在客户端实现服务绑定并用AIDL存根作为通讯接口
  2. 利用存根中的方法实现需求功能

在本例中,我们将实现一个进行四则运算计算器,以及一个计算器的服务器。计算器通过绑定到服务器上的服务来完成计算功能

阅读须知

本文可以仅需要RPC基础和c语言基础,对于java中类的继承、抽象类、方法等概念只需初步了解,无需Android开发经验

示例开发

安装android虚拟机的方法

  • 首先找到设备管理器

在这里插入图片描述

  • 然后点击创建设备

在这里插入图片描述

  • 没有特殊需求就选默认硬件,直接点next
  • 操作系统映像选默认的(和硬件匹配的)点Download,许可协议选accept然后再点next就开始下载了。我这里是已经装好了

在这里插入图片描述

开启USB调试的方法

这个各个设备不太一样,一般要先在设备信息界面点击某个信息十次解锁,比如我是点击设置-设备信息-软件信息-编译编号解锁开发者模式

解锁了之后在设置-开发者选项里找到USB调试打开就可以了。

1.创建服务端项目,编写AIDL代码

创建新项目

从左上角File-New-New Project新建项目,注意选择"Empty Activity"

在这里插入图片描述

接下来可以点next,但在最后的界面记得把语言改成java,项目名字我这里后来改成了AidlServer

在这里插入图片描述

创建新的包

在项目列表里选择java目录,右键,点击new,点击Package,在目录结构里选main

在这里插入图片描述

给它起个名字,注意过会需要创建这个包的一个副本,所以名字别起太怪,不方便检查。我这里是叫AIDLPackage

创建新的AIDL文件

刚才的创建的包上右键创建AIDL文件,名字也别起太怪,我这里叫IAidlDemo

在这里插入图片描述

应该能在新建的Aidl文件中看到如下的代码:

// IAidlDemo.aidl
package AidlPackage;

// Declare any non-default types here with import statements

interface IAidlDemo {
    /**
     * 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);
}

编写接口定义

我们要把计算的过程委托给远程服务器,也就是传递两个运算数和一个运算符,接受一个结果。方便起见,规定运算是整数运算,并且用1 2 3 4表示+ - * /,这样我们就形成了如下接口:

// IAidlDemo.aidl
package AidlPackage;

// Declare any non-default types here with import statements

interface IAidlDemo {
    int calculate(int v1, int v2, int op);
}

然后需要点击Build-Rebuild Project或者点击右上角配置栏左侧的绿色小锤子进行Make Project。注意,每次修改AIDL文件都要进行rebuild
到此为止,我们的服务应用程序框架就创建完成。

2.注册服务,实现方法

在APP里右键创建新的Service,注意不要Service(Intent Service),在接下来的窗口里enabledexported都要选中

在这里插入图片描述

新建存根

打开新建的服务的java代码app/java/AidlPackage/<ServiceName>.java,为<ServiceName>类添加一个存根变量

private final IAidlDemo.Stub
...

注意,这里按下.之后,应该提示后面的Stub类型,如果没有提示就说明刚才没有进行Rebuild!点击下图所示绿色小锤子进行Rebuild

在这里插入图片描述

确认自己rebuild完成之后继续写。

private final IAidlDemo.Stub = new IAidlDemo.

现在应该能自动补全Stub了,按Tab键之后,就应该出现类似下面的内容:

private final IAidlDemo.Stub stub = new IAidlDemo.Stub() {
        @Override
        public int calculate(int v1, int v2, int op) throws RemoteException {
            return 0;
        }
    };
    //不会自动打分号

注意到calculate正是我们之前定义的接口定义语言,因为AIDL生成的存根类型是个抽象类,因此系统会自动提醒我们复写其中的calculate方法。

实现方法

接下来,我们就来修改这个存根的内部的方法,这里就简单的复制一份代码吧!

private final IAidlDemo.Stub stub = new IAidlDemo.Stub() {
        @Override
        public int calculate(int v1, int v2, int op) throws RemoteException {
            switch (op) {
                case 1:
                    return v1 + v2;
                case 2:
                    return v1 - v2;
                case 3:
                    return v1 * v2;
                case 4:
                    return  v1 / v2;
                default:
                    Log.e("Error: ","Invalid Operator");
                    return 0;
            }
        }
    };
    //记得打分号

由于这是一个远程方法,因此默认可能会抛出一个远程异常,不过我们不必管他,一般不会出现这种情况。

传递存根

<ServiceName>.java中应该还有一个默认的方法onBind:

@Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

这是因为我们的服务继承了Service抽象类,因此需要实现onBind方法,也就是指定当服务绑定时要进行的操作。我们只需要返回刚才创建的存根即可。

@Override
    public IBinder onBind(Intent intent) {
        return stub;
    }

到此为止我们的服务端项目就编写完成,可以跑一下试试看:

在这里插入图片描述

虽然没有UI界面,但是服务已经就绪了~

3.创建客户端项目,拷贝AIDL

新建客户端项目可以单开一个project也可以就在这个project里操作,这里选择单开一个project。过程就不再赘述,注意仍然用Empty Activity作为界面。

这里仍然在app\java上右键,选New-Package新建包,注意包名要与刚刚创建的包名相同
在包上右键,新建Aidl文件,注意文件名要和刚刚创建的文件相同
复制刚刚的Aidl文件内容,粘贴到新的Aidl文件里
包名、文件名、文件内容完全相同。
在这里插入图片描述

4.设计客户端UI

打开activity_main.xml默认在创建项目的时候就会有这个文件生成,如果不小心关掉了就从左侧项目目录app/res/layout/目录下打开。
请检查一下这个目录,确保其中只有activity_main.xml。在右上角选择以Code方式查看该文件的内容:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MvkQBALs-1649828149801)(开发AIDL示例项目的完整流程/layout.bmp)]

文件内容应该如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

这个xml制定了应用程序主界面的UI,如果layout文件夹里有多个文件或者这个.xml文件的内容和上述内容不一样,那么很有可能是因为你没有选择EmptyActivity类型的项目,你可自行判断是否需要重建项目。如果你不清楚这个.xml文件的具体行为,可以考虑重建。

接下来我们还是在右上角将视图切换到View,或者你也可以直接复制本项目的.xml文档,直接跳到实现业务逻辑的部分

修改布局

默认的布局是constraint,这样图标的上下左右位置都需要指定,很麻烦,于是我们把所有的androidx.constraintlayout.widget.ConstraintLayout修改为RelativeLayout

  <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ <RelativeLayout xmlns: xmlns:android="http://schemas.android.com/apk/res/android"

...


- </androidx.constraintlayout.widget.ConstraintLayout>
+ </RelativeLayout>

如果修改成功,Android应该没有任何Warning,并且你会发现Hello World从原来的居中变为出现在左上角。(要查看.xml的效果,你可以在右上角选择SplitView模式)

添加TextView

我们需要一个文本框来显示结果,把下面这段话粘贴到.xml中,并且删除Hello World(从< 开始删除到 >为止)

    <TextView
        android:id="@+id/display_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_margin="20dp"
        android:background="#FDF171"
        android:hint="Result"
        android:padding="15dp"
        android:textSize="20sp"
        android:textStyle="bold" />

现在你应该看到这样的文本框:

在这里插入图片描述

所以TextView就是一个文本框,我们设置了默认显示的字符串(hint)、背景颜色、字号、字体等内容信息,还设置了长宽、水平居中、边距等定型定位尺寸。我们可以在java代码中和TextView进行沟通,比如通过setText方法来设置要显示的内容,这样我们就可以把结果输出到这个文本框里。
还有值得注意的一点是,每个组建都拥有自己的id,比如@+id/display_result就对应我们刚刚的文本框,因为我们的第一行就指明了他的id。这个id1可以在xml中描述组件之间的相对关系,也可以在java中用于绑定组件信息。

添加EditText

我们需要两个文本框来接受输入的运算数

    <EditText
        android:id="@+id/enter_first_value"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_below="@+id/display_result"
        android:layout_marginStart="20dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:ems="10"
        android:hint="Enter First Value"
        android:imeOptions="actionNext"
        android:inputType="number"
        android:maxLength="5"
        android:singleLine="true" />

    <EditText
        android:id="@+id/enter_next_value"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_below="@+id/enter_first_value"
        android:layout_marginStart="20dp"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="20dp"
        android:layout_marginBottom="20dp"
        android:autofillHints=""
        android:ems="10"
        android:hint="Enter Next Value"
        android:inputType="number"
        android:maxLength="5"
        android:singleLine="true" />

开头是一个id号,而所有含有layout的都是定型尺寸和定位尺寸,这里注意layout_below指明它要放在上面那个文本框的下方。这里还限制了输入类型是数字,最多输入5个且只接受单行输入。

添加按钮

首先添加四则运算,这四个按钮之间的位置关系通过layout_belowlayout_toEndOf来指定,可以看到加法减法位于同一行,乘法除法位于同一行,减法除法在加法乘法右侧。
按钮默认全字大写,所以这里关闭了textAllCaps

    <Button
        android:id="@+id/add"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/enter_next_value"
        android:layout_marginLeft="20dp"
        android:background="#0288D1"
        android:text="Add"
        android:textAllCaps="false"
        android:textColor="#ffff" />

    <Button
        android:id="@+id/subtract"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/enter_next_value"
        android:layout_marginStart="20dp"
        android:layout_toEndOf="@+id/add"
        android:background="#0288D1"
        android:text="Subtract"
        android:textAllCaps="false"
        android:textColor="#ffff" />

    <Button
        android:id="@+id/multiply"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/add"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp"
        android:background="#0288D1"
        android:text="Multiply"
        android:textAllCaps="false"
        android:textColor="#ffff" />

    <Button
        android:id="@+id/divide"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/subtract"
        android:layout_marginStart="20dp"
        android:layout_marginTop="10dp"
        android:layout_toEndOf="@+id/multiply"
        android:background="#0288D1"
        android:text="Divide"
        android:textAllCaps="false"
        android:textColor="#ffff" />

这两个按钮是用于清零和绑定服务的,让他们居中。

        <Button
            android:id="@+id/clear_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/division"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"
            android:text="Clear Data" />

        <Button
            android:id="@+id/bind_service"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/clear_data"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp"
            android:text="Bind Service" />

整体效果应该如图:
在这里插入图片描述

注意,各个按钮之间的相对关系是通过id指定的,如果更改了id多半会有error,修改id修复error即可
另外会有一些warning,比如叫你把字符串做编码之类的,建议不懂的话忽略就好

这就是我们的ui界面了!AndroidUI的设计还是很简洁的,但是背后是项目自动为我们生成的许多文件~

更多内容请期待下一篇~

举报

相关推荐

0 条评论