AIDL
原理图:
语法
// 包名, 文件必须放在指定的目录 package com.your.package // 定义接口 interface IRemoteService { // 定义方法 int getPid(int pid);}
创立 AIDL 文件,并生成 Java 接口类
- 手动
- 主动
手动
- 创立与 java 同级的目录 aidl
- 在这个目录下创立和 java 包下一样的包构造
- 编写 aidl 文件
- 用
~/Library/Android/sdk/build-tools/30.0.3/aidl
(我本人电脑的门路) 下的 aidl 命令生成 Java 接口文件
主动
- 在 main 目录上点击右键
- new -> AIDL : 会主动创立一个 aidl 文件
- 点击 build -> Make Project 就会生成相应的 Java 接口文件(文件门路:YourProject/app/build/generated/aidl_source_output_dir/debug/out/cn/kk/myaidl/)
残缺操作步骤
- 创立 AIDL 文件
- 生成对应 Java 接口类
- 定义 Service, 并在 AndroidManifest.xml 中注册
- 在自定义的 Service 类中定义成员变量 Binder, 并且初始化(实现接口办法)
- 在自定义的 Service 类的 onBind() 办法中,返回步骤 4 定义的 Binder 对象。
- 新建客户端的 module, 将服务端的 aidl -> 包名 目录下的所有文件拷贝到客户端 aidl -> 包名(和服务端包名要一样) 目录下
- 客户端绑定服务端
- 在客户端调用服务端定义的办法
3. 定义 Service 并注册
在 AndroidManifest.xml 中注册:
<service android:name=".MyCalculatorService" android:process=":remote" android:enabled="true" android:exported="true"> </service>
7. 客户端绑定服务端
步骤 6 操作完,Make Project(在客户端依据 aidl 定义的接口 生成 Java 类)。
// 客户端绑定服务端 Intent intent = new Intent(); String aidlPackageName = "cn.kk.myaidl"; // 近程 aidl 的包名 String aidlRemoteServiceName = "cn.kk.myaidl.MyCalculatorService"; // 要绑定的近程服务名 intent.setComponent(new ComponentName(aidlPackageName, aidlRemoteServiceName)); // Context.BIND_AUTO_CREATE 绑定后,服务主动启动 bindService(intent, conn, Context.BIND_AUTO_CREATE); // 创立成员变量 ServiceConnection conn private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { } @Override public void onServiceDisconnected(ComponentName name) { }}; // 定义成员变量: private IMyCalculatorService iMyCalculatorService; // 在回调办法 onServiceConnected() 里, 初始化 iMyCalculatorService: private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iMyCalculatorService IMyCalculatorService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { // 回收资源 iMyCalculatorService = null; } };
默认反对的数据类型
- 根本数据类型(不包含 short)
- String, CharSequence
- List, Map
- Parcelable
创立自定义类型的数据(罕用)
服务端操作:
- 创立 Human.java 类。
- 序列化这个类
- 创立 Human.aidl 文件
- 在 AIDL 接口文件中,应用 Human 自定义类型
- Make Project
- 在服务端的 Service 外面实例化接口,重写接口办法, onBind() 外面返回这个实例化对象
2.序列化这个类
- 实现接口:Parcelable
- 重写办法:describeContents() 和 writeToParcel(Parcel dest, int flags)
- writeToParcel() 办法重写:
dest.writeString(name); dest.writeInt(age); ...
- 实例化变量:Creator<Human> CREATOR
- 创立 Human 新的构造方法:
4.实例化变量:Creator<Human> CREATOR
public static final Creator<Human> CREATOR = new Creator<Human>() { @Override public Human createFromParcel(Parcel source) { return new Human(source); } @Override public Human[] newArray(int size) { return new Human[0]; } };
5.创立 Human 新的构造方法:
public Human(Parcel source) { // 这个操作程序肯定要和 writeToParcel() 的程序统一 this.name = source.readString(); this.age = source.readInt(); }
3.创立 Human.aidl 文件
在 aidl 目录中,参照 Human.java 的包名,在对应的门路创立 Human.aidl 文件,内容如下:
package cn.kk.myaidl.bean; parcelable Human;
4.在 AIDL 接口文件中,应用 Human 自定义类型
- 导入自定义类:
import cn.kk.myaidl.bean.Human;
- 定义方法,如:
List<Human> addHuman(in Human h);
6.在服务端的 Service 外面实例化接口,重写接口办法
private IBinder iHumanBinder = new IHumanInterface.Stub() { @Override public List<Human> addHuman(Human h) throws RemoteException { humanArrayList.add(h); return humanArrayList; } };
客户端操作:
- 将服务端新最新的 aidl 文件都复制过去
- 将服务端定义的类型:Human.java 连同包构造复制到客户端 src/main/java/ 下
-
在 Activity 中绑定服务的回调用,用 iHumanInterface(IHumanInterface 类型) 接管返回值:
private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { iHumanInterface = IHumanInterface.Stub.asInterface(service); Log.d(TAG, "onServiceConnected: "); } @Override public void onServiceDisconnected(ComponentName name) { // 回收资源 // iMyCaculatorService = null; iHumanInterface = null; Log.d(TAG, "onServiceDisconnected: "); } };
- 新创建一个点击事件,在点击事件中操作新的接口:
private List<Human> add(Human human) throws RemoteException { return iHumanInterface.addHuman(human); } btnAddHuman.setOnClickListener(v -> { try { add(new Human("秦始皇",33)); add(new Human("汉武帝",53)); add(new Human("唐太宗",55)); List<Human> humans = add(new Human("宋太祖", 65)); for (Human human : humans) { Log.d(TAG, "onClick: " + human.getName() + "," + human.getAge()); } } catch (RemoteException e) { e.printStackTrace(); } });
- 运行(先启动服务端,再启动客户端)后输入日志:
onClick: 秦始皇,33 onClick: 汉武帝,53 onClick: 唐太宗,55 onClick: 宋太祖,65
代码之后再上传。。。