在学习 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
在app上点击右键->新建->AIDL->AIDL文件
给我们新建的aidl文件起个名字IMyBookManager。
创建一个Book.java的类,Book的类必须与IMyBookManager的是同一个命名空间。
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,或者点击菜单进行编辑。
编译完成这后系统会自动的生成一个实现类,这个是有系统生成的,不需要我们关系,我们需要处理的只是实现个类,继承系统给我们生成的这个类的子类。
好了我们现在添加 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
生成的代码
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的子类,我来看看他是什么样子的
我们发现 Stub 是集成了 Binder 的类,我们再看看Binder类
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"/> 是我们为我们的服务定义的一个调用名称,这个自己可以任意的起。当然要符合命名规范。
到处我们的服务就能够正常的工作了,可以对外提供接口服务了。