Android AIDL 教程 (一)—— 简单的示例

  • 在 AndroidManifet 配置 Service,将我们的 Service 暴露出去。

将请求抽象成接口,编写 aidl 文件

一般来说, AIDL 文件支持以下类型

  • Java 编程语言中的所有原语类型(如 int、long、char、boolean 等等)

  • String

  • CharSequence

  • List

List 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 可选择将 List 用作“通用”类(例如,List)。另一端实际接收的具体类始终是 ArrayList,但生成的方法使用的是 List 接口。

  • Map

Map 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 不支持通用 Map(如 Map<String,Integer> 形式的 Map)。 另一端实际接收的具体类始终是 HashMap,但生成的方法使用的是 Map 接口。

  • 实现 Parceable 的自定义类型

注意事项

  • 在 aidl 文件中,除了 Java 编程语言中的所有原语类型、String、CharSequence、List、Map,其他在 AIDL 文件中用到的类,你必须使用 import 语句导入,否则会报错。

  • 当你使用实现Parceable 的自定义类型的时候,当其作为参数的时候,你必须为其制定是输入或者是输出参数。

in 表示输入参数,即服务端可以修改该类型

out 表示输出参数,即客户端可以修改该类型,客户端不行

inout 表示客户端和服务端都可以修改该类型

void onSuccess(int code,in MusicInfo musicInfo);

有人可能会这样想,既然 inout 表示客户端和服务端都可以修改该类型,那我们平时在写 aidl 文件的时候,直接在方法参数前面加上 inout 修饰就 OK了,省得去区分。

这样做法当然不行,既然双方都可以修改,那系统的开销肯定会比较大。就好比管道一样。

说了这么多,接下来让我们一起来看一下例子 IEasyService.aidl

package xj.musicserver.easy;

// Declare any non-default types here with import statements

interface IEasyService {

/**

  • Demonstrates some basic types that you can use as parameters

  • and return values in AIDL.

*/

void connect(String mes);

void disConnect(String mes);

}

这个 aidl 文件很接口,只有两个方法,connect 和 disConnect 方法。

在这里插入图片描述

这里我们把 aidl 文跟 Java 文件中放在一起,需要在 build.gradle 中配置

sourceSets {

main {

jniLibs.srcDirs = [‘libs’]

aidl.srcDirs = [‘src/main/java’]

}

}

关于怎样在 AndroidStudio 中引用 aidl 文件的,可以参考我的这一篇文章 AndroidStudio 引用 aidl 文件的两种方法

编写一个 Service,实现接口,处理客户端的请求,并将接口返回回去

public class EasyService extends Service {

private static final String TAG = “EasyService”;

public EasyService() {

}

IEasyService.Stub mIBinder=new IEasyService.Stub() {

@Override

public void connect(String mes) throws RemoteException {

LogUtil.i(TAG,“connect: mes =” + mes);

}

@Override

public void disConnect(String mes) throws RemoteException {

LogUtil.i(TAG, “disConnect: mes =” +mes);

}

};

@Override

public IBinder onBind(Intent intent) {

LogUtil.i(TAG,"onBind: intent = "+intent.toString());

return mIBinder;

}

@Override

public boolean onUnbind(Intent intent) {

LogUtil.i(TAG,“onUnbind: =”);

return super.onUnbind(intent);

}

@Override

public void onDestroy() {

LogUtil.i(TAG,“onDestroy: =”);

super.onDestroy();

}

}

这个 Service 所做的动作就是当客户端连接上的时候,会启动我们的 Service,此时会调用 Service 的 onBInd 方法,在 onBinder 方法里面,我们将 mIBinder (实现了 IEasyService.Stub 接口)返回回去。他充当客户端和服务端的桥梁,通过他我们可以进行通讯。

至于这个 IEasyService.Stub 是什么呢?其实当我们在 AndroidStudio 里面编写完 aidl 文件,重新 make project 一下,就会自动生成了。

将服务端的 Service 暴露出去

在 AndroidManifest 文件下,配置 Service 的 action 及 exported 等信息。

其中 android:exported=“true” 表示别的进程可以访问,这个是必须配置的。android:process=“:remote” 表示运行在 :remote 进程,不配置的话默认运行所在的 App 进程,这个可以不配置。

<service

android:name=“.easy.EasyService”

android:enabled=“true”

android:exported=“true”

android:process=“:remote”>


客户端的实现


  • 将服务端的 aidl 文件 copy 过来,注意要放在同一个包下

  • 通过服务端 Service 的 Action 启动, 当启动 Service 成功的时候,将服务端返回的 Binder 保存下来并转化成相应的实例。

  • 之后如果想与服务端通讯,通过保存下来的 Binder,即可调用服务端的方法。

第一步:将服务端的 aidl 文件 copy 过来,注意要放在同一个包下

在这里插入图片描述

  • 第二步,通过服务端 Service 的 Action 启动, 当启动 Service 成功的时候,将服务端返回的 Binder 保存下来并转化成相应的实例

当我们点击按钮的时候,我们通过 Action 去启动远程 servic。

case R.id.btn_start_service:

LogUtil.i(TAG,“onButtonClick: btn_start_service=”);

Intent intent = new Intent(ACTION);

// 注意在 Android 5.0以后,不能通过隐式 Intent 启动 service,必须制定包名

intent.setPackage(XJ_MUSICSERVER);

bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);

private static final String ACTION = “xj.musicserver.easy.IEasyService”;

private IEasyService mIEasyService;

ServiceConnection mServiceConnection=new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

mIEasyService = IEasyService.Stub.asInterface(service);

}

@Override

public void onServiceDisconnected(ComponentName name) {

mIEasyService=null;

}

};

测试将会启动远程 Service,及服务端的 EasyService,并调用 onBind 方法,打印出相应信息。

xj.musicserver:remote I/MusicInterface: EasyService :onBind: intent = Intent { act=xj.musicserver.easy.IEasyService pkg=xj.musicserver }

第三步:如果想与服务端通讯,通过保存下来的 Binder,即可调用服务端的方法。

比如当我们点击按钮的时候,调用 connect 方法。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

架构师筑基包括哪些内容

我花了将近半个月时间将:深入 Java 泛型.、注解深入浅出、并发编程.、数据传输与序列化、Java 虚拟机原理、反射与类加载、高效 IO、Kotlin项目实战等等Android架构师筑基必备技能整合成了一套系统知识笔记PDF,相信看完这份文档,你将会对这些Android架构师筑基必备技能有着更深入、更系统的理解。

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容

注:资料与上面思维导图一起看会更容易学习哦!每个点每个细节分支,都有对应的目录内容与知识点!



这份资料就包含了所有Android初级架构师所需的所有知识!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

、高效 IO、Kotlin项目实战等等**Android架构师筑基必备技能整合成了一套系统知识笔记PDF,相信看完这份文档,你将会对这些Android架构师筑基必备技能有着更深入、更系统的理解。

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容

注:资料与上面思维导图一起看会更容易学习哦!每个点每个细节分支,都有对应的目录内容与知识点!

[外链图片转存中…(img-izzxLSAQ-1713074372816)]
[外链图片转存中…(img-6ibkHHOJ-1713074372816)]
这份资料就包含了所有Android初级架构师所需的所有知识!

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单Android AIDL 示例代码: 首先,需要定义一个 AIDL 接口文件,例如 MyService.aidl: ``` package com.example.myservice; interface MyService { String getMessage(); } ``` 然后在服务端实现这个接口,例如 MyService.java: ``` package com.example.myservice; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class MyService extends Service { private final MyServiceImpl mImpl = new MyServiceImpl(); private static class MyServiceImpl extends IMyService.Stub { @Override public String getMessage() { return "Hello from MyService!"; } } @Override public IBinder onBind(Intent intent) { return mImpl; } } ``` 最后,在客户端绑定服务并调用接口方法,例如 MainActivity.java: ``` package com.example.myapplication; 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.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.example.myservice.MyService; public class MainActivity extends AppCompatActivity { private MyService mService; private boolean mBound = false; private final ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = MyService.Stub.asInterface(service); mBound = true; // 调用 MyService 中定义的接口方法 try { String message = mService.getMessage(); TextView textView = findViewById(R.id.text_view); textView.setText(message); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mService = null; mBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定 MyService Intent intent = new Intent(); intent.setComponent(new ComponentName("com.example.myservice", "com.example.myservice.MyService")); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); if (mBound) { unbindService(mConnection); mBound = false; } } } ``` 鉴于这只是一个简单示例,实际的应用场景可能会更加复杂。需要注意的是,AIDL 接口中定义的方法的参数和返回值必须是支持跨进程传输的类型,例如基本类型、String、Parcelable 等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值