Android AIDL 学习 (服务端)

在学习 AIDL的过程中看不过不少的书籍,在网上也找了不少的资料,总算能够实现AIDL的调用,在这里把自己的理解与实现写出来方便一后备忘查找。

主要是自己的底子太差,别人都写的太高大尚很多看不明白。用自己看明白的方式记录下。

话不多说回归正题。

AIDL是什么

AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。

它就是可以定义一个接口,提供给其他的app调用。

为什么会需要AIDL语音接口

每一个app的运行在虚拟机中都有自己独立的进程,虚拟机为每个app进行划分独立的内存运行空间,app就在这个空间里运行无法越界。

那有自己的独立空间是挺好,程序运行起来互相不影响,但有些时候自己想要获取的数据,自己没法完成只有别的app才能够提供,但自己由跑不出去虚拟机给划分的空间,那怎么办?这时AIDL就来了,app之间只要根据统一的规则,双双规定好接口就能够通过AIDL进行传输数据。

A (客户端)说想从B (服务器端)进行登录的验证,B服务端返回成功还是失败,能够从B端获取一个对象。

我们就以这个小需求为列,看看AIDL需要怎么实现。

首先我们来看服务端,服务端提供服务,那我就是老大,一切规则由我定,你们都是小弟必须按照我的规则来。

我们来看看服务端如何实现。

环境:android stuido 3.6.2

新建一个项目BService

Android AIDL 学习 (服务端)

Android AIDL 学习 (服务端)

在app上点击右键->新建->AIDL->AIDL文件

Android AIDL 学习 (服务端)

 给我们新建的aidl文件起个名字IMyBookManager。Android AIDL 学习 (服务端)

 创建一个Book.java的类,Book的类必须与IMyBookManager的是同一个命名空间。

Android AIDL 学习 (服务端)

Android AIDL 学习 (服务端)

package com.example.bservice;

public class Book {
    private int price;
    private String name = "";

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Book 这个类,后续我们需要通过AIDL 接口返回给调用者,所以这个类需要进行序列化。

我们让他实现 Parcelable接口。

package com.example.bservice;

import android.os.Parcel;
import android.os.Parcelable;

public class Book implements Parcelable {
    private int price;
    private String name = "";

    public Book(){}

    protected Book(Parcel in) {
        price = in.readInt();
        name = in.readString();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(price);
        dest.writeString(name);
    }
}

处理完了Book类,我们来处理我们的接口文件  IMyBookManager

IMyBookManager.aidl接口文件中我们实现两个接口,1个是登录login,一个是根据书名返回一个Book的类。

// IMyBookManager.aidl
package com.example.bservice;

// Declare any non-default types here with import statements
//需要采用全部包名的引入。
import com.example.bservice.Book;

//需要说明我们引入的book 是个序列化的类。
parcelable Book;

interface IMyBookManager {
    /**
     * 默认添加的基础类型接口,不用可以删掉
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    String login(String userName, String pwd);
    
    Book queryByName(String bookName);
}

 处理完了接口文件之后,我们编译一下,按ctrl+f9,或者点击菜单进行编辑。

Android AIDL 学习 (服务端)

编译完成这后系统会自动的生成一个实现类,这个是有系统生成的,不需要我们关系,我们需要处理的只是实现个类,继承系统给我们生成的这个类的子类。

Android AIDL 学习 (服务端)

好了我们现在添加  MyBookManager 继承  IMyBookManager.Stub类。

package com.example.bservice;

import android.os.RemoteException;

public class MyBookManager extends IMyBookManager.Stub {
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
        
    }

    @Override
    public String login(String userName, String pwd) throws RemoteException {
        return null;
    }

    @Override
    public Book queryByName(String bookName) throws RemoteException {
        return null;
    }
}

 上面是个框架,下面我们进行简单的具体实现。

package com.example.bservice;

import android.os.RemoteException;

public class MyBookManager extends IMyBookManager.Stub {
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

    }

    @Override
    public String login(String userName, String pwd) throws RemoteException {
        if(userName.equalsIgnoreCase("abcd") && pwd.equalsIgnoreCase("123")){
            return "success";
        }
        return "error";
    }

    @Override
    public Book queryByName(String bookName) throws RemoteException {
        Book book = new Book();
        book.setName(bookName);
        book.setPrice(100);
        return book;
    }
}

好了这样我们就对接口进行了一个简单的实现。

说了这么多还是没说到底该怎么用,现在我就来说说该怎么用。

想对外提供给其他的app调用我们还需要创建一个服务,通过服务的绑定方法进行对外进行服务。

好了我们添加个服务吧。

我们先添加个报名 service,全路径为 com.example.bservice.service

Android AIDL 学习 (服务端)

Android AIDL 学习 (服务端) 生成的代码

package com.example.bservice.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MyService extends Service {
    public MyService() {
    }

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

 还记得我们刚才添加了个 MyBookManager的实现类吧,他集成了IMyBookManager.Stub的子类,我来看看他是什么样子的

Android AIDL 学习 (服务端)

我们发现 Stub 是集成了 Binder 的类,我们再看看Binder类

Android AIDL 学习 (服务端)

Binder类实现了IBinder的接口,而我们的Service 真好也有个Bind的方法是返回IBinder这接口。

那我们就可以吧我们的 MyBookManager通过这个接口返回给调用者。

最终我们的 MyService 代码。把我们的接口实现类给返回。

package com.example.bservice.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import com.example.bservice.MyBookManager;

public class MyService extends Service {
    
    MyBookManager bookManager = new MyBookManager();
    
    public MyService() {
    }

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

接口的实现类完成了,服务也添加了,那我们的服务要想在外边能被调用,我们还差最后一步,需要再AndroidManifest.xml 文件中对齐进行设置。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.bservice">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service
            android:name=".service.MyService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote"
            >
            <intent-filter>
                <action android:name="com.example.bservice.bookService"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 <action android:name="com.example.bservice.bookService"/> 是我们为我们的服务定义的一个调用名称,这个自己可以任意的起。当然要符合命名规范。

到处我们的服务就能够正常的工作了,可以对外提供接口服务了。

上一篇:dubbo2.5.6从下载到编译成功并且部署成功过程


下一篇:Day78--阶段复习03--Django框架