android AIDL使用demo

背景

最近打算学习一下如何在framework层添加一个自定义service。
了解到自定义service需要使用aidl,为了加强对aidl的了解和使用过程,特意又温习了一下aidl的使用,并用博客的形式记录下来。
aidl官方参考:https://developer.android.google.cn/develop/background-work/services/aidl?hl=en

AIDL是什么

官方解释:Android 接口定义语言 (AIDL) 类似于其他 IDL:它允许您定义客户端和服务使用进程间通信 (IPC) 进行相互通信时都认可的编程接口。

定义 AIDL 接口

project结构图
这里我使用的ide是Android Studio Iguana版本。
首先创建一个project,里面创建两个app一个叫client,另一个叫server。
在server app的src/main目录创建一个aidl文件IMyAidlInterface.aidl,内容如下

// IMyAidlInterface.aidl
package com.hai.server;
// Declare any non-default types here with import statements
//aidl说明参考:https://developer.android.google.cn/develop/background-work/services/aidl?hl=en
interface IMyAidlInterface {/*** 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);int getPid();oneway void getThreadId();
}

IMyAidlInterface.aidl中定义了三个接口供客户端调用。

然后编译一下project,就会在server的build目录下自动生成IMyAidlInterface.java接口文件,内容如下

/** This file is auto-generated.  DO NOT MODIFY.*/
package com.hai.server;
// Declare any non-default types here with import statements
//aidl说明参考:https://developer.android.google.cn/develop/background-work/services/aidl?hl=en
public interface IMyAidlInterface extends android.os.IInterface
{/** Default implementation for IMyAidlInterface. */public static class Default implements com.hai.server.IMyAidlInterface{/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException{}@Override public int getPid() throws android.os.RemoteException{return 0;}@Override public void getThreadId() throws android.os.RemoteException{}@Overridepublic android.os.IBinder asBinder() {return null;}}/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.hai.server.IMyAidlInterface{/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/*** Cast an IBinder object into an com.hai.server.IMyAidlInterface interface,* generating a proxy if needed.*/public static com.hai.server.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.hai.server.IMyAidlInterface))) {return ((com.hai.server.IMyAidlInterface)iin);}return new com.hai.server.IMyAidlInterface.Stub.Proxy(obj);}@Override public android.os.IBinder asBinder(){return this;}@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{java.lang.String descriptor = DESCRIPTOR;if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {data.enforceInterface(descriptor);}switch (code){case INTERFACE_TRANSACTION:{reply.writeString(descriptor);return true;}}switch (code){case TRANSACTION_basicTypes:{int _arg0;_arg0 = data.readInt();long _arg1;_arg1 = data.readLong();boolean _arg2;_arg2 = (0!=data.readInt());float _arg3;_arg3 = data.readFloat();double _arg4;_arg4 = data.readDouble();java.lang.String _arg5;_arg5 = data.readString();this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);reply.writeNoException();break;}case TRANSACTION_getPid:{int _result = this.getPid();reply.writeNoException();reply.writeInt(_result);break;}case TRANSACTION_getThreadId:{this.getThreadId();break;}default:{return super.onTransact(code, data, reply, flags);}}return true;}private static class Proxy implements com.hai.server.IMyAidlInterface{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}@Override public android.os.IBinder asBinder(){return mRemote;}public java.lang.String getInterfaceDescriptor(){return DESCRIPTOR;}/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeInt(anInt);_data.writeLong(aLong);_data.writeInt(((aBoolean)?(1):(0)));_data.writeFloat(aFloat);_data.writeDouble(aDouble);_data.writeString(aString);boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}@Override public int getPid() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result;try {_data.writeInterfaceToken(DESCRIPTOR);boolean _status = mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);_reply.readException();_result = _reply.readInt();}finally {_reply.recycle();_data.recycle();}return _result;}@Override public void getThreadId() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);boolean _status = mRemote.transact(Stub.TRANSACTION_getThreadId, _data, null, android.os.IBinder.FLAG_ONEWAY);}finally {_data.recycle();}}}static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);static final int TRANSACTION_getThreadId = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);}public static final java.lang.String DESCRIPTOR = "com.hai.server.IMyAidlInterface";/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;public int getPid() throws android.os.RemoteException;public void getThreadId() throws android.os.RemoteException;
}

IMyAidlInterface.java结构图
IMyAidlInterface.java结构图

可以看到IMyAidlInterface.java也定义了和aidl相同的三个接口,并且定义了DefaultStub两个静态内部类去实现IMyAidlInterface接口。

  • Default类默认空实现且没有继承Binder,实际无意义。
  • Stub是一个继承Binder抽象类,实际是要在server端写一个Stub的实现类去实现实际的接口功能
  • Stub.Proxy一般用于client端。

Server端实现服务

接下来就是在server端的service中实现aidl接口服务,这里我写了一个ServerService类,内容如下

package com.hai.server;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.system.Os;
import android.util.Log;public class ServerService extends Service {private static final String TAG = "ServiceService";IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() {@Overridepublic void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {Log.d(TAG, "basicTypes() called with: anInt = [" + anInt + "], aLong = [" + aLong + "], aBoolean = [" + aBoolean + "], aFloat = [" + aFloat + "], aDouble = [" + aDouble + "], aString = [" + aString + "]");}@Overridepublic int getPid() throws RemoteException {SystemClock.sleep(2000);return Os.getpid();}@Overridepublic void getThreadId() throws RemoteException {SystemClock.sleep(2000);}};@Overridepublic IBinder onBind(Intent intent) {Log.d(TAG, "onBind() called with: intent = [" + intent + "]");return binder;}@Overridepublic boolean onUnbind(Intent intent) {Log.d(TAG, "onUnbind() called with: intent = [" + intent + "]");return super.onUnbind(intent);}
}

为了client端可以通过隐式服务绑定服务,还需要在AndroidManifest.xml做一下配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.AidlDemo"><serviceandroid:name=".ServerService"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.hai.server.ServerService" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></service></application>
</manifest>

当client端通过bindservice绑定成功后,服务端就会返回server端的binder对象给到client端。

Client端使用服务

首先需要把server端的aidl整个文件夹拷贝到client端的src目录,以便client端能够获得aidl的访问权限。client端的代码结构如图
在这里插入图片描述
编译一下project,就会在client的build目录下自动生成IMyAidlInterface.java接口文件。
接下来就是bindservice,bindservice服务成功后就可以获得binder的代理对象,进而调用aidl接口服务。如下是在activity中通过bindservice的方式调用aidl接口服务。

package com.hai.aidldemo;import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;import com.hai.server.IMyAidlInterface;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";IMyAidlInterface myAidlInterface;ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.d(TAG, "onServiceConnected() called with: name = [" + name + "], service = [" + service + "]");myAidlInterface = IMyAidlInterface.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {Log.d(TAG, "onServiceDisconnected() called with: name = [" + name + "]");}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);}public void clk(View view) {switch (view.getId()) {case R.id.btn_bind:if (myAidlInterface == null) {boolean b = bindService(new Intent("com.hai.server.ServerService").setPackage("com.hai.server"), serviceConnection, Context.BIND_AUTO_CREATE);Log.d(TAG, "bindService: " + b);}break;case R.id.btn_unbind:if (myAidlInterface != null) {unbindService(serviceConnection);}break;case R.id.btn_basicType:try {myAidlInterface.basicTypes(1, 2, true, 4, 5, "6");} catch (RemoteException e) {throw new RuntimeException(e);}break;case R.id.btn_getPid:try {long start = System.currentTimeMillis();int pid = myAidlInterface.getPid();Log.d(TAG, "getPid: " + pid + ", cost:" + (System.currentTimeMillis() - start));} catch (RemoteException e) {throw new RuntimeException(e);}break;case R.id.btn_getThreadId:try {long start = System.currentTimeMillis();myAidlInterface.getThreadId();Log.d(TAG, "getThreadId: cost:" + (System.currentTimeMillis() - start));} catch (RemoteException e) {throw new RuntimeException(e);}break;}}
}

项目源码:

https://gitee.com/menty/aidl-demo/blob/master/client/src/main/java/com/hai/aidldemo/MainActivity.java

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/36879.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++ 初阶路】--- 类和对象(末)

目录 一、const成员1.1 取地址及const取地址操作符重载 二、再谈构造函数2.1 构造函数体赋值2.2 初始化列表2.3 explicit关键字 三、static成员3.1 概念3.2 特性 四、友元4.1 友元函数4.2 友元类 五、内部类六、匿名对象 一、const成员 将const修饰的“成员函数”称之为const成…

多行业预约门店服务小程序源码系统 支持多门店预约 带完整的安装代码包以及搭建教程

系统概述 该系统基于先进的云计算和大数据技术&#xff0c;采用模块化设计&#xff0c;具有高度的可扩展性和可定制性。无论是餐饮、美容美发、健身房还是其他服务行业&#xff0c;都可以通过该系统轻松实现多门店预约功能。同时&#xff0c;我们还提供了丰富的接口和插件&…

Pagehelper超级好用的分页插件

目录 一&#xff1a;pagehelper介绍 二&#xff1a;pagehelper使用 2.1导入pagehelper依赖 2.2在resources资源下配置application.yml配置文件 2.3 配置Mybatis 2.4编写Mapper和xml文件 三&#xff1a;常见问题及解决方案 一&#xff1a;pagehelper介绍 PageHelper是一款基…

CSS基础汇总

CSS 1. 选择器 标签选择器 通过标签名找标签&#xff08;把指定的样式应用到某一个、组、类标签上&#xff09; id选择器 通过id属性值找标签&#xff0c;关键符号#id值{样式} 复合选择器 1、并列选择器&#xff1a;关键符号&#xff0c;用法&#xff1a;选择器1&#xff0c…

Appium+python自动化(二十九)- 模拟手指在手机上多线多点作战 - 多点触控(超详解)

简介 在网页中我们经常使用缩放操作来便利的查看具体的信息&#xff0c;在appium中使用MultiAction多点触控的类来实现。MultiAction是多点触控的类&#xff0c;可以模拟用户多点操作。主要包含加载add()和执行perform()两个方法. 问题思考 在使用地图App中&#xff0c;我们…

Lyapunov-Krasovskii泛函三重积分项求导_原理

Lyapunov-Krasovskii泛函三重积分项求导_原理 1 Lyapunov-Krasovskii泛函三重积分项举例2 Lyapunov-Krasovskii泛函三重积分项求导3 基于辅助函数的一重积分不等式4 基于辅助函数的二重积分不等式 本人为研二小白&#xff0c;在看论文的过程中记录一下自己的学习过程和想法。 在…

ORACLE同步数据(dblink+物化视图)

1.创建dblink create public database link xirEvalDBlink connect to "XIR_TRD" identified by "xpar" USING (DESCRIPTION (ADDRESS (PROTOCOL TCP)(HOST 191.168.0.11)(PORT 1521)) (CONNECT_DATA (SERVER DEDICATED) (SERVICE_NAME orcl) ) )…

nginx 配置页面重定向,并携带链接和参数

期望 将 ip:port//oldPrefix/pages?a1 重定向到ip:port//oldPrefix/targetPrefix?a1 nginx 配置 # 原始前缀 # permanent 重定向 location /oldPrefix/ {rewrite ^/oldPrefix/(.*)$ /targetPrefix/$1 permanent; }# 目标前缀 location /targetPrefix/ {# 相关配置 }

echarts实现堆叠图加折线混合图

vue组件实现代码: <template><div :id="chartId" style="width: 100%; height: 300px"></div> </template><script>import * as echarts from "echarts";export default {name: "doubleStackLine", /…

Embedding 、词嵌入、向量模型说的是一回事么?AI是如何理解世界?AI人不能不看的Embedding白话科普!

在AI理解世界的过程中&#xff0c;向量模型扮演着一个至关重要的角色&#xff0c;甚至可以说它是AI大模型用以构建和理解复杂数据的基础&#xff0c;也是对不同形态数据的一种标准化的“浓缩”。它能够将语言、图像、声音等多样化的信息&#xff0c;转化为一种通用的、数学化的…

pg_rewind实现原理简单分析

pg_rewind的功能是在主备切换后回退旧主库上多余的事务变更&#xff0c;以便可以作为新主的备机和新主建立复制关系。通过pg_rewind可以在故障切换后快速恢复旧主&#xff0c;避免整库重建。对于大库&#xff0c;整库重建会很耗时间。 如何识别旧主上多余的变更&#xff1f; 这…

基于51单片机的银行排队呼叫系统设计

一.硬件方案 本系统是以排队抽号顺序为核心&#xff0c;客户利用客户端抽号&#xff0c;工作人员利用叫号端叫号&#xff1b;通过显示器及时显示当前所叫号数&#xff0c;客户及时了解排队信息&#xff0c;通过合理的程序结构来执行排队抽号。电路主要由51单片机最小系统LCD12…

K8S Pod常见状态

这是自己所遇到 Pod 常见状态及可能原因&#xff0c;持续更新。 如有其他的错误状态&#xff0c;可私我更新 1. ImagePullBackOff 问题分析&#xff1a; 镜像拉取失败。 可能原因&#xff1a; 可能是网络问题导致&#xff0c;检查Pod所在节点是否能够正常访问网络; 镜…

Vue-cli项目及Element UI 环境搭建 保姆级教程

一、Vue-cli介绍及其作用 什么是Vue-cli手脚架 vue-cli 官方提供的一个脚手架&#xff0c;用于快速生成一个 vue 的项目模板&#xff1b;预先定义 好的目录结构及基础代码&#xff0c;就好比咱们在创建 Maven 项目时可以选择创建一个 骨架项目&#xff0c;这个骨架项目就是脚…

electron本地运行请求端口

本地运行&#xff1a; npm run electron:start 运行后项目请求地址为&#xff1a; http://localhost:5173/api/xxxx const {protocol } require(electron); app.commandLine.appendSwitch(--ignore-certificate-errors, true); // Scheme must be registered before the app…

手把手教你玩转AD9361数字调制解调系列(二) ----纯逻辑实现FSK信号的数字调制解调

因最近客户需求&#xff0c;用纯PL实现AD9361的数字信号调制解调&#xff0c;于是就把各种数字调制都在AD9361上都实现了一遍。优点就是&#xff1a;既可以在zynq系列上配置9361&#xff0c;也可以在纯FPGA系列配置9361。并且理解起来比较简单&#xff01;&#xff01;&#xf…

lidar3607.2 雷达点云数据处理软件功能介绍

LiDAR360 是北京数字绿土科技股份有限公司自主研发的点云后处理及行业应用软件。平台可处理 TB 级点云数据&#xff0c;并拥有 10 余种国际领先的点云处理及 AI 算法&#xff0c;推动激光雷达 的多行业应用。700 余项强大且灵活的功能&#xff0c;解决用户最后一公里的应用难题…

云仓是如何发展起来的?

1、电子商务的繁荣&#xff1a; 随着电商的兴起&#xff0c;对高效仓储和物流的需求越来越大。传统的仓储方式难以满足海量订单处理和快速配送的要求&#xff0c;因此需要一种更加灵活和高效的仓储解决方案。 ------------------------------------------------- 2、科技进步…

速盾:cdn动态加速上传

CDN&#xff08;Content Delivery Network&#xff0c;内容分发网络&#xff09;是一种通过在全球范围内分布的服务器群组来提供高速、可靠内容传递的技术。CDN在网络上广泛应用&#xff0c;可以加速网站中的静态内容和动态内容的传输&#xff0c;并提高用户的访问速度和体验。…

Nuxt 的路由结构系统(七)

基本路由配置 在 Nuxt.js 中&#xff0c;每个 .vue 文件在 pages/ 目录下都会自动成为一个路由。文件名决定了路由的路径。例如&#xff1a; pages/ |-- index.vue # 映射到根路径 / |-- about.vue # 映射到路径 /about |-- contact.vue # 映射到路径 /conta…