Android生成Java AIDL

AIDL:Android Interface Definition Language

AIDL是为了实现进程间通信而设计的Android接口语言

Android进程间通信有多种方式,Binder机制是其中最常见的一种

AIDL的本质就是基于对Binder的运用从而实现进程间通信

这篇博文从实战出发,用一个尽可能精简的Demo,实现两个App(也是两个进程:服务端mainapp、客户端otherapp)通过AIDL的跨进程通信

一.创建两个App


按照下列步骤先创建两个App:

(1).新建一个开发文件夹(本Demo中命名为aidl-test)

(2).使用AndroidStudio在aidl-test文件夹下创建第一个Empty Activity的空App:mainapp

为了后续方便起见

创建完成后,把Studio默认创建的MainActivity.java名字改一下,改成MainAppActivty.java

(3).创建第二个Empty Activity的空App:otherapp

两个空App创建完成了:

二.在mainapp中创建一个Service

上一节中新建了两个空App:mainappotherapp

现在就先在mainapp中实现一个service

使用方便又快捷的studio创建MainAppService.java

 

可以看到新建的MainAppService会自动实现一个onBind(Intent intent)方法,这个方法后续我会在其中进行代码实现,它需要在其他进程连接到Service时,返回一个继承了android.os.Binder的对象

先在 MainAppActivity 和 MainAppService 中添加一些必要的生命周期函数代码
再在 MainAppService 中添加:
onBind(Intent intent):被客户端绑定时执行
onUnbind(Intent intent):被客户端解绑时执行

@com/android/mainapp/MainAppActivity.javapackage com.android.mainapp;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;public class MainAppActivity extends AppCompatActivity {private String TAG = "AIDL-MainAppActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.v(TAG, "onCreate()");setContentView(R.layout.activity_main);}@Overrideprotected void onDestroy() {super.onDestroy();Log.v(TAG, "onDestroy()");}
}
@com/android/mainapp/MainAppService.java package com.android.mainapp;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;public class MainAppService extends Service {private String TAG = "AIDL-MainAppService";public MainAppService() {}@Overridepublic void onCreate() {super.onCreate();}@Overridepublic void onStart(Intent intent, int startId) {Log.v(TAG, "onStart()");}@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException("Not yet implemented");}@Overridepublic boolean onUnbind(Intent intent) {Log.v(TAG, "onUnbind()");return true;}@Overridepublic void onDestroy() {super.onDestroy();Log.v(TAG, "onDestroy()");}
}

三.mainapp中实现AIDL

依然使用方便又快捷的AndroidStudio在mainapp的main目录下创建一个名为IAppAidlInterface.aidl 的AIDL文件

 

AndroidStudio创建 IAppAidlInterface.aidl 会自动实现一个默认的可用于进程间传参通信的void basicTypes(...)函数,其参数是java的几种基础数据类型

除此之外,AIDL还支持多种其他数据类型:byte、short、char、charSequence、 List、 Map等

除了AndroidStudio自动创建的basicTypes(...)函数,我在AIDL文件里面再新增一个setData(..)函数,用于后面跨进程的数据传输,虽然使用AndroidStudio自动生成的basicTypes(...)也是可以的,但是自己创建一个函数会更具有代表性.

在本篇博文最开始就阐述过,AIDL的本质是对Binder的运用,从而实现进程间通信

那么现在Binder在哪呢?

IAppAidlInterface.aidl文件创建之后,build一下工程,AndroidStudio会在build目录下创建一个aidl_source_output_dir文件夹,同时在这个文件夹下创建与IAppAidlInterface.aidl包名、文件名相同的文件夹目录和java文件

IAppAidlInterface.java文件中通过继承android.os.Binder创建一个抽象的代理类stub,这个stub抽象代理类主要做如下几件事:

通过stub自身实例实现进程内部的通信
通过实现一个内部代理类Porxy用于跨进程通信
重写Binder中的onTransact()函数,实现AIDL接口文件中声明的函数进行数据传输
传输的数据必须是序列化的android.os.Parcel类型数据 

 

当然,如果项目需要对AIDL的Binder实现过程进行自定义封装,方便项目中对进程间通信机制进行定制化,那么,完全可以不采用AndroidStudio自动生成的IAppAidlInterface.java,只须要按照自己的需要实现IAppAidlInterface.java中对Binder进程间通信的实现过程就行了

因为归根结底,AIDL实现进程间通信的基础就是Binder机制,只要使用Binder实现AIDL进程间通信的目的就可以了

IAppAidlInterface.java就先讨论到这里,这篇博文主要是对AIDL的使用进行研究,其对Binder机制的实现与封装不在此做深入探讨

后续会专门开一篇博文讲解AIDL对Binder机制的内部实现,以及用户如何自定义封装

四.otherapp中也实现AIDL


上一节中,作为服务端的mainapp里创建了一个AIDL文件,客户端的otherapp中也需要实现一份相同的AIDL,要不然客户端就无法引用到了对应的函数和stub等了

很简单,把mainapp中的AIDL文件整个包名目录直接拷贝到otherapp中即可,然后再build一下工程

 

接下来,需要添加一些代码,实现客户端otherapp与服务端mainapp的相连

五.mainapp中添加代码


前文中已经展示过,MainAppService会随着MainAppActivity的onCreate()和onDestroy()生命周期startService()和stopService()

mainapp中要添加的代码在MainAppService.java中,需要在MainAppService中做下面一些事情:

  • 使用匿名内部类实现IAppAidlInterface.Stub抽象类,用于实现IAppAidlInterface.aidl中的接口函数和onBinder()时返回匿名内部类实例
  • onBinder()中启动一个线程,每1秒轮循接收客户端发送过来的数据

 这里提到个题外的知识点,Service中除了onBinder()函数外还有个onRebind()函数

      如果同一客户端每次unBindService()之后再bindService()并且发送的Intent也一样,那么onBind()就只会在服务端第一次被这个客户端连接时才执行,后续重连时都不会再执行了。

     而onRebind()在服务端第一次被连接时不会被执行,但是之后每次重连都会执行,不论Intent是否一样。

    如果想要onBind()在同一客户端连接时都能执行,客户端在每次bindService()时,改变发送Intent的type或其他成员变量就行了

定义一个string变量用于接收客户端传过来的字符串,定义一个boolean变量用于控制线程

AndroidMainfest.xml中为MainAppService添加Service标签

六.otherapp中添加代码

otherapp里面主要需要做如下几件事:

  • 新建一个Intent,用于连接服务端mainapp
    IntentComponent设置为Sevice的包名和类名
  • 新建两个button,用于控制bindService()绑定和unbindService()解绑
  • 重写Service连接和断开的两个基础函数onServiceConnected()onServiceDisconnected()
  • AndroidMainfest.xml中添加查询包名权限,以便otherapp可以查询到mainapp,或者直接指定查询mainapp的包名

 

七.运行、验证 

到此,一个最基础的使用AIDL实现两个App(服务端mainapp、客户端otherapp)之间通信的demo代码就完成了,下面我们来验证一下。

编译、安装apk:

项目build Apk后会生成两个apk,两个都install上

 

运行验证:

注:本demo中代码的所有日志TAG都加上了AIDL前缀,方便日志打印验证

先启动一下mainapp,MainAppService不会被启动但是会被注册到系统,因为在mainapp的AndroidMainfest.xml中对MainAppService进行了Service标签添加。

 

退出mainapp后,再打开otherapp:

现在执行几次"Bind Service"和"Unbind Service",就会看到如下日志打印:

好,通过这个精简Demo,初步实现了两个App通过AIDL的跨进程通信 

 

八.源代码

接下来逐一展示实现的源码

mainapp源码:

D:\Codes\aidl-test\app\src\main\aidl\com\android\mainapp\IAppAidlInterface.aidl

// IAppAidlInterface.aidl
package com.android.mainapp;// Declare any non-default types here with import statementsinterface IAppAidlInterface {/*** 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);void setStringData(String strData);
}

 

D:\Codes\aidl-test\app\src\main\java\com\android\mainapp\MainAppActivity.java

package com.android.mainapp;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;public class MainAppActivity extends AppCompatActivity {private String TAG = "AIDL-MainAppActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.v(TAG, "onCreate()");setContentView(R.layout.activity_main);}@Overrideprotected void onDestroy() {super.onDestroy();Log.v(TAG, "onDestroy()");}
}

D:\Codes\aidl-test\app\src\main\java\com\android\mainapp\MainAppService.java

package com.android.mainapp;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;public class MainAppService extends Service {private String TAG = "AIDL-MainAppService";private String mStrData;private boolean mSetServiceRunning = true;public MainAppService() {}@Overridepublic void onCreate() {super.onCreate();Log.v(TAG, "onStart()");}@Overridepublic void onStart(Intent intent, int startId) {Log.v(TAG, "onStart()");}IAppAidlInterface.Stub mStub = new IAppAidlInterface.Stub() {@Overridepublic void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {}@Overridepublic void setStringData(String strData) {mStrData = strData;}};@Overridepublic IBinder onBind(Intent intent) {Log.v(TAG, "onBind()");mSetServiceRunning = true;new Thread() {@Overridepublic void run() {super.run();while (mSetServiceRunning) {try {Thread.sleep(1000);Log.v(TAG, "mStrData:"+mStrData);} catch (InterruptedException e) {e.printStackTrace();}}}}.start();return mStub;}@Overridepublic boolean onUnbind(Intent intent) {Log.v(TAG, "onUnbind()");mSetServiceRunning = false;return true;}@Overridepublic void onDestroy() {super.onDestroy();Log.v(TAG, "onDestroy()");}
}

D:\Codes\aidl-test\app\src\main\AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.Mainapp"tools:targetApi="31"><serviceandroid:name=".MainAppService"android:enabled="true"android:exported="true"></service><activityandroid:name=".MainAppActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><meta-dataandroid:name="android.app.lib_name"android:value="" /></activity></application></manifest>

 

otherapp源码: 

D:\Codes\aidl-test\otherapp\src\main\aidl\com\android\mainapp\IAppAidlInterface.aidl

// IAppAidlInterface.aidl
package com.android.mainapp;// Declare any non-default types here with import statementsinterface IAppAidlInterface {/*** 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);void setStringData(String strData);
}

D:\Codes\aidl-test\otherapp\src\main\java\com\android\otherapp\OtherAppMainActivity.java

package com.android.otherapp;import androidx.appcompat.app.AppCompatActivity;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 com.android.mainapp.IAppAidlInterface;public class OtherAppMainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {private String TAG = "AIDL-OtherAppActivity";private int mICount = 0;private Intent mServiceIntent;private IAppAidlInterface mBinder;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_other_app_main);mServiceIntent = new Intent();mServiceIntent.setComponent(new ComponentName("com.android.mainapp", "com.android.mainapp.MainAppService"));findViewById(R.id.btnBindMainAppService).setOnClickListener(this);findViewById(R.id.btnUnBindMainAppService).setOnClickListener(this);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.btnBindMainAppService: {Log.v(TAG, "onClick():btnBindMainAppService");bindService(mServiceIntent, this, Context.BIND_AUTO_CREATE);}break;case R.id.btnUnBindMainAppService: {Log.v(TAG, "onClick():btnUnBindMainAppService");unbindService(this);mBinder = null;}break;}}@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {if (mBinder == null) {mBinder = IAppAidlInterface.Stub.asInterface(iBinder);mICount++;Log.v(TAG, "onServiceConnected() 第 " + mICount + " 次");try {String strData = "第" + mICount + "次连接Service成功!";mBinder.setStringData(strData);} catch (RemoteException e) {e.printStackTrace();}}}@Overridepublic void onServiceDisconnected(ComponentName componentName) {Log.v(TAG, "onServiceDisconnected");}
}

 

D:\Codes\aidl-test\otherapp\src\main\res\layout\activity_other_app_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns: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"android:orientation="vertical"tools:context=".OtherAppActivity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textAllCaps="false"android:text="OtherApp"/><Buttonandroid:id="@+id/btnBindMainAppService"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textAllCaps="false"android:text="Bind  Service" /><Buttonandroid:id="@+id/btnUnBindMainAppService"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textAllCaps="false"android:text="UnBind Service" /></LinearLayout>

D:\Codes\aidl-test\otherapp\src\main\AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"><!--<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>--><queries><package android:name="com.android.mainapp"/></queries><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.Mainapp"><activityandroid:name=".OtherAppMainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><meta-dataandroid:name="android.app.lib_name"android:value="" /></activity></application></manifest>

 

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

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

相关文章

【深度学习】Pytorch基础

目录 梯度下降算法&#xff08;Gradient Descent&#xff09;代码实现 梯度下降算法&#xff08;Gradient Descent&#xff09; 梯度下降算法在机器学习中应用十分的广泛&#xff0c;不论是在线性回归还是Logistic回归中&#xff0c;它的主要目的是通过迭代找到目标函数的最小…

python-游戏自动化(三)(实战-豆腐女孩)

前提准备 特别注意&#xff1a; 本节教程所演示的模拟器分辨率设置为 720x1080&#xff08;手机版&#xff09;&#xff0c;电脑分辨率设置大720x1080并且没有设置放大。 今天的课程开始之前我们来回顾一下昨天所学的知识内容&#xff0c;因为今天要学的内容和昨天内容…

苹果能引领端侧AI大模型时代吗?

苹果能引领端侧AI时代吗&#xff1f; 这份完整版的大模型 AI 学习资料已经上传CSDN&#xff0c;朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】 北京时间9月10日凌晨&#xff0c;苹果正式发布了iPhone 16&#xff0c;这是苹果第一款真正意义上的 …

网络安全(sql注入)

这里写目录标题 一. information_schema.tables 和 information_schema.schemata是information_schema数据库中的两张表1. information_schema.schemata2. information_schema.tables 二. 判断注入类型1. 判断数字型还是字符型注入2. 判断注入闭合是""还是 三. 判断表…

浅谈模型在信贷营销中的应用

浅谈模型在信贷营销中的应用 当前在信贷营销场景中,用户流量竞争愈加激烈,获客成本持续攀高,客户消费观念和消费信心趋向保守,传统的信贷营销方式效果逐渐乏力,借助数据挖掘技术对用户进行多元优化及精细化管理已经成为企业在经营发展中的普遍趋势。在此背景下,本文将围…

什么是API网关(API Gateway)?

1. 什么是API网关&#xff08;API Gateway&#xff09;&#xff1f; 在微服务体系结构中&#xff0c;客户端可能与多个前端服务进行交互。 API 网关位于客户端与服务之间。 它充当反向代理&#xff0c;将来自客户端的请求路由到服务。 它还可以执行各种横切任务&#xff0c;例…

什么是CPU、GPU、NPU?(包懂+会)

目录 举例子 CPU&#xff1a;主厨 GPU&#xff1a;大量的厨房助理 NPU&#xff1a;面包机 总结 讲理论 CPU&#xff08;中央处理器&#xff09; GPU&#xff08;图形处理单元&#xff09; NPU&#xff08;神经网络处理单元&#xff09; 对比分析 举例子 CPU&#xff…

【网络安全】-文件下载漏洞-pikachu

文件操作漏洞包括文件上传漏洞&#xff0c;文件包含漏洞&#xff0c;文件下载漏洞。 文章目录  前言 什么是文件下载漏洞&#xff1f; 1.常见形式&#xff1a; 常见链接形式&#xff1a; 常见参数&#xff1a; 2.利用方式&#xff1a; 3.举例&#xff1a;pikachu不安全的文件…

【Qt】按钮样式--按钮内部布局(调整按钮文本和图标放置在任意位置)

要求&#xff1a; 有一个按钮&#xff0c;要求按钮的右下角显示开关&#xff0c;点击切换开关状态 ps&#xff1a;注意&#xff0c;要求你添加完了之后&#xff0c;整个按钮的点击区域不变&#xff08;就是说&#xff0c;点击右下角的文本&#xff0c;也可以触发按钮的点击事件…

CentOS7 使用yum报错:[Errno 14] HTTP Error 404 - Not Found 正在尝试其它镜像。

CentOS7 使用yum报错&#xff1a;[Errno 14] HTTP Error 404 - Not Found 正在尝试其它镜像。 CentOS镜像下载、VM虚拟机下载 下载地址&#xff1a;www.macfxb.cn 一、问题描述 安装完CentOS7 后 使用yum报错 如下图 二、解决方案 1.查看自己的系统架构 我的是aarch64 uname …

python 学习一张图

python学习一张图&#xff0c;python的特点的是学的快&#xff0c;一段时间不用&#xff0c;忘记的也快&#xff0c;弄一张图及一些入门案例吧。 写一个简单的测试&#xff1a; #!/usr/bin/python # -*- coding: UTF-8 -*- import osdef add_num(a, b):return a bif __name__…

【STM32】BH1750光敏传感

1.BH1750介绍 BH1750是一个光敏传感&#xff0c;采用I2C协议&#xff0c;对于I2C的从机&#xff0c;都有自己的地址&#xff0c;用来主机选择和哪个从机通信&#xff0c;对于OLED来说&#xff0c;只有单片机通过I2C往OLED中写数据。而BH1750来说&#xff0c;有单片机往BH1750写…

DNAT和SNAT实践

NAT分SNAT和DNAT两种。从名字上区分&#xff1a; SNAT将源IP地址替换为出口网络的IP地址&#xff0c;以便内网地址可以访问外网服务。一般受限于公网IP有限&#xff0c;一个内网集合想访问外网服务&#xff0c;则用统一的出口做代理。出口配置公网IP&#xff0c;帮助从此发出的…

Note24091101_基恩士日期获取相关测试01

基恩士日期获取相关测试 1、SEC和RSEC的使用&#xff1a; 资料如图&#xff1a; 要点提示&#xff1a;SEC和RSEC成对使用。 日期转秒&#xff0c;秒转日期测试如图所示&#xff1a; 2. LDWK与LDWKB星期接点的使用示例&#xff1a; 资料如图&#xff1a; 仿真如图&…

2018年系统架构师案例分析试题五

目录 案例 【题目】 【问题 1】(7 分) 【问题 2】(12 分) 【问题 3】(6 分) 【答案】 【问题 1】解析 【问题 2】解析 【问题 3】解析 相关推荐 案例 阅读以下关于 Web 系统设计的叙述&#xff0c;在答题纸上回答问题 1 至问题 3。 【题目】 某银行拟将以分行为主体…

287. 寻找重复数(stl法)

目录 一&#xff1a;题目&#xff1a; 二&#xff1a;代码&#xff1a; 三&#xff1a;结果&#xff1a; 一&#xff1a;题目&#xff1a; 给定一个包含 n 1 个整数的数组 nums &#xff0c;其数字都在 [1, n] 范围内&#xff08;包括 1 和 n&#xff09;&#xff0c;可知…

数模方法论-线性规划

一、基本概念 在实际生产过程中&#xff0c;人们经常面临如何有效利用现有资源来安排生产&#xff0c;以实现最大经济效益的问题。这类问题构成了运筹学的一个重要分支——数学规划&#xff0c;而线性规划&#xff08;Linear Programming, LP&#xff09;是数学规划中的一个关键…

Facebook的虚拟现实计划:未来社交的全新视角

随着科技的不断进步&#xff0c;虚拟现实&#xff08;VR&#xff09;正逐步成为我们日常生活的一部分。作为全球领先的社交平台&#xff0c;Facebook正在大力投入虚拟现实技术&#xff0c;以重新定义社交互动的方式。本文将深入探讨Facebook的虚拟现实计划&#xff0c;分析其如…

网络高级(学习)2024.9.11

目录 Modbus库函数 1.初始化和释放函数 2.功能函数 3.功能案例 Modbus RTU 1.特点 2.协议格式 3.编程思路 Modbus库函数 1.初始化和释放函数 modbus_t* modbus_new_tcp(const char *ip, int port) 功能&#xff1a;以TCP方式创建Modbus实例&#xff0c;并初始化 参数…

基于vue框架的城市智慧地铁管理系统73c2d(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,站点查询,车次线路,站点周边 开题报告内容 基于Vue框架的城市智慧地铁管理系统开题报告 一、研究背景与意义 1.1 研究背景 随着城市化进程的加速和人口的不断增长&#xff0c;城市交通压力日益增大。地铁作为城市公共交通的重要…