Android中使用AIDL实现进程通信

news/2025/1/3 4:22:16/

前言

关于使用AIDL实现两个APP(跨进程)通信,我们通常把两个APP分别叫做服务端和客户端。本文不讲原理,只给最简易的案例。

一、服务端APP实现

1. 在src/main/aidl目录下新建一个.aidl文件,然后在.aidl文件中定义需要开放的接口,如下:在这里插入图片描述

package com.test.aidl;import com.test.aidl.ActionCallback;interface OpenData {void cycleData(String linData);boolean handshake(int cmdNumber);void listenerData(ActionCallback actionCallback);}
package com.test.aidl;interface ActionCallback {void callback(String jsonData);}

2. 点击工具栏Bulid模块中的Make Project时,会在build目录下生成编译文件,如下所示:

在这里插入图片描述
值得注意的是,编译出来的文件中,默认增加了一个stub内部类,这个stub类是Binder的子类,如下所示:
在这里插入图片描述

3.定义一个Service,然后把上一步的Stub类实例化,把Stub的对象return给Service的onBind方法,如下所示:

package com.test.server;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.test.aidl.ActionCallback;
import com.test.aidl.OpenData;public class ListenerService extends Service {private static final int NOTIFICATION_ID = 1;private final OpenData.Stub binder = new OpenData.Stub() {@Overridepublic void cycleData(String linData) throws RemoteException {Log.e("MyAidlData", "------------------cycleData---------------------");Log.e("MyAidlData", "Data=" + linData);}@Overridepublic boolean handshake(int cmdNumber) throws RemoteException {Log.e("MyAidlData", "------------------handshake---------------------");Log.e("MyAidlData", "Data=" + cmdNumber);return true;}@Overridepublic void listenerData(ActionCallback actionCallback) throws RemoteException {Log.e("MyAidlData", "------------------listenerData---------------------");if (actionCallback == null) {Log.e("MyAidlData", "Data=无效监听");try {actionCallback.callback("无效监听");} catch (RemoteException e) {e.printStackTrace();}} else {Log.e("MyAidlData", "Data=监听成功");try {actionCallback.callback("监听成功");} catch (RemoteException e) {e.printStackTrace();}}}};@Overridepublic IBinder onBind(Intent intent) {return binder;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return START_STICKY;}}

注意:Service需要再AndroidManifest.xml中注册,并增加相关属性的申明,如下:

<serviceandroid:name="com.test.server.ListenerService"android:exported="true"><!--条件测试7————必须为true--><!--隐式启动:当有匹配<intent-filter>的意图发送时,系统可能会根据定义的过滤规则选择合适的服务进行启动。这种方式依赖于是否有其他组件发送了符合过滤条件的意图。--><intent-filter><!--条件测试6————必须要与客户端的action一致--><action android:name="AAaaBB"/></intent-filter>
</service>

二、客户端APP实现

1. 在src/main/aidl目录下新建一个.aidl文件,然后在.aidl文件中定义需要开放的接口代码,如下:

特别注意:这里的【.aidl文件内容】和【文件路径】必须和服务端APP完全一致。

在这里插入图片描述

2. 在客户端APP的AndroidManifest.xml文件中增加必须的权限:

<!--条件测试3————必须--><uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />

3. 封装一个AIDL客户端管理类,如下:

package com.test.client;import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;import com.test.aidl.ActionCallback;
import com.test.aidl.OpenData;public class AIDLClient {private AIDLClient() {}private static class Holder{public static final AIDLClient INSTANCE=new AIDLClient();}public static AIDLClient getInstance(){return Holder.INSTANCE;}private OpenData openData;private ServiceConnection connection;/*** 1.初始化服务连接*/public void initConnection(){connection = new ServiceConnection() {public void onServiceConnected(ComponentName className, IBinder service) {openData = OpenData.Stub.asInterface(service);Log.d("初始化链接", "连接成功");}public void onServiceDisconnected(ComponentName className) {openData = null;Log.d("初始化链接", "连接断开");}};}/*** 2.获取链接* @return*/public ServiceConnection getConnection() {return connection;}//Tx (分享出去的数据)___________________________________________________________________public boolean sendCycleData(String cycleData){try {if (openData!=null){openData.cycleData(cycleData);return true;}else {return false;}} catch (RemoteException e) {Log.e("AIDL链接异常",e.toString());return false;}}public boolean sendHandShake(int number){try {if (openData!=null){openData.handshake(number);return true;}else {return false;}} catch (RemoteException e) {Log.e("AIDL链接异常",e.toString());return false;}}//Rx (接收服务端发来的数据————回调方式实现)______________________________________________________public boolean registerListener(){try {if (openData!=null){//这里new MyCall()后期可以把MyCall也变成单例可能更适合(看需求)openData.listenerData(new MyCall());return true;}else {return false;}} catch (RemoteException e) {Log.e("AIDL链接异常",e.toString());return false;}}private class MyCall extends ActionCallback.Stub{@Overridepublic void callback(String jsonData) throws RemoteException {Log.e("绑定服务","回调数据="+jsonData);}}}

4. 把客户端绑定到服务端去,并发送数据,代码如下:

package com.test.client;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//第一步:初始化AIDLClient.getInstance().initConnection();//第二步:绑定服务Intent intent = new Intent();intent.setAction("AAaaBB");//条件测试6————必须与服务端指定的service的name一致intent.setPackage("com.test.aidltest1");//这个包名必须写服务端APP的包名boolean re=bindService(intent, AIDLClient.getInstance().getConnection(), Context.BIND_AUTO_CREATE);Log.e("绑定服务",re ? "成功":"失败");//第三步:发送数据findViewById(R.id.startSend1).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AIDLClient.getInstance().sendCycleData("哈哈哈哈");}});findViewById(R.id.startSend2).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AIDLClient.getInstance().sendHandShake(666);}});findViewById(R.id.startSend3).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AIDLClient.getInstance().registerListener();}});}
}

有问题,评论区见!


http://www.ppmy.cn/news/1559629.html

相关文章

【Golang 面试题】每日 3 题(十一)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…

金蝶V10中间件的使用

目录 环境准备搭建过程配置修改应用部署 环境准备 Linux内核服务器JDK1.8安装包&#xff1a;AAS-V10.zip程序包&#xff1a;***.war 搭建过程 将安装包上传至服务器opt目录下&#xff0c;官方给定的默认服务主目录为“/opt/AAS-V10/ApusicAS/aas/”&#xff1b;解压安装包(解…

【ARM】PK51关于内存模式的解析与区别

1、 文档目标 解决PK51中三种内存模式所对应的不同场景选择。 2、 问题场景 在PK51中有三种内存模型可以进行选择&#xff0c;但是这三种内存模型的具体作用以及应用场景大部分工程师都不太清楚。 图2-1 3、软硬件环境 1&#xff09;、软件版本&#xff1a;Keil PK51 9.60 …

leecode198.打家劫舍

动态规划&#xff0c;dp[i]表示经过第i个房屋时能偷取到的最高金额&#xff0c;由于相邻房屋不能偷&#xff0c;所以dp[i]偷取当前房屋加上上次偷取的钱与不偷取当前房屋的钱二者取最大值 class Solution { public:int rob(vector<int>& nums) {if(nums.size()1)ret…

Day2 微服务 网关路由转发、网关登录校验、配置管理

目录 1.网关路由转发 1.1 网关 1.2 快速入门 1.2.1 创建项目 1.2.2 引入依赖 1.2.3 启动类 1.2.4 配置路由 1.2.5 测试 1.3 路由过滤 2.网关登录校验 2.1 鉴权思路分析 2.2 网关过滤器 2.3 自定义过滤器 2.3.1 自定义GatewayFilter 2.3.2 自定义GlobalFilter 2.4 登录校验 2.4.…

PyTorch快速入门教程【小土堆】之损失函数与反向传播

视频地址损失函数与反向传播_哔哩哔哩_bilibili Loss两个作用 1,计算实际输出和目标之间的差距 2. 为我们更新输出提供一定的依据&#xff08;反向传播) import torch from torch import nn from torch.nn import L1Lossinputs torch.tensor([1, 2, 3], dtypetorch.float3…

苍穹外卖day07缓存部分分析

苍穹外卖Day07部分聚焦于缓存功能的实现与优化&#xff0c;通过引入redis缓存机制&#xff0c;结合Spring Cache 注解&#xff0c;降低了数据库负载&#xff0c;提升其响应速度。 以下是清除缓存功能代码&#xff1a; RestController RequestMapping("/admin/dish"…

Spring Cloud由入门到精通

文章目录 1.初识微服务1.1. 单体架构1.2.分布式架构1.3.微服务1.4 微服务技术比对1.5.Spring Cloud1.6. 总结2.服务拆分和远程调用2.1.服务拆分原则2.2.服务拆分示例2.2.1.项目工程结构设计2.2.2.创建Maven项目工程2.3.实现远程调用案例2.3.1.案例需求:2.3.2. 注册 Rest Templ…