Android -- 每日一问:AIDL是什么?你有使用过它吗,它支持哪些数据类型?
Posted Kevin-Dev
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android -- 每日一问:AIDL是什么?你有使用过它吗,它支持哪些数据类型?相关的知识,希望对你有一定的参考价值。
经典回答
什么是 AIDL
AIDL 是 android Interface Definition Language 的简写,即 Android 接口定义语言。我们知道 Android 系统为每一个应用开启一个独立的虚拟机,每个应用都运行在各自进程里(默认情况下),彼此之间相互独立,无法共享内存。当一个应用想要访问另一个应用的数据或调用其方法,就要用到 Android 系统提供的 IPC 机制。而 AIDL 就是 Android 实现 IPC 机制的方式之一。
除了 AIDL,Android 还提供了 Messenger 来实现跨进程通信,不过 Messenger 是以单线程串行方式(消息队列)来处理来自不同客户端的访问的,并不适合多线程并发访问。当需要提供跨进程以及多线程并发服务时就需要 AIDL 上场了。
Messenger 实际上也是以 AIDL 作为其底层结构。
使用 AIDL 进行进程间通信
1. 创建 .aidl 文件
我们在对应的 src 的 Package 下创建一个 AIDL 文件(Android Studio->File->New->AIDL->AIDL file),创建后Android Studio会自动把这个.aidl文件放到一个aidl的目录下。
Android SDK Tool 会根据我们的 .aidl 文件自动生成一个同名的 .java 文件,如:AIDLTest/app/build/generated/source/aidl/debug/net/goeasyway/aidltest/IRemoteService.java
basicTypes 方法中给我们展示了 AIDL 支持的基本数据类型,除此之外,AIDL 还支持:CharSequence, List & Map(List和Map中的所有元素都必须是AIDL支持的数据类型、其他AIDL生成的接口或您声明的可打包类型。)
2. 创建一个 Service 暴露 AIDL 接口并实现 AIDL 的接口函数
public class RemoteService extends Service
public RemoteService()
@Override
public IBinder onBind(Intent intent)
return binder; //暴露给客户端
// 实现AIDL接口
private final IRemoteService.Stub binder = new IRemoteService.Stub()
@Override
public int getPid() throws RemoteException
return Process.myPid();
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException
;
然后在 MainActivity 通过 bindService 绑定这个服务,即可以获得 AIDL 的接口调用的引用。运行前,我们设置一下 AndroidManifest.xml 文件记这个 Service 运行在一个单独的进程中:
<service
android:name=".RemoteService"
android:process=":remote"
android:enabled="true"
android:exported="true"/>
现在来 bindService:
public class MainActivity extends AppCompatActivity
private final static String TAG = "MainActivity";
private IRemoteService remoteService;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClass(this, RemoteService.class);
bindService(intent, connection, Service.BIND_AUTO_CREATE); // 绑定服务
private ServiceConnection connection = new ServiceConnection()
public void onServiceConnected(ComponentName className, IBinder service)
remoteService = IRemoteService.Stub.asInterface(service); //获取AIDL的接口实现引用
try
Log.i(TAG, "Client pid= " + Process.myPid());
Log.i(TAG, "RemoteService pid= " + remoteService.getPid());
catch (RemoteException e)
e.printStackTrace();
public void onServiceDisconnected(ComponentName className)
Log.e(TAG, "Service has unexpectedly disconnected");
remoteService = null;
;
到这里,我们完成了一个 AIDL 的示例代码。
通过 IPC 传递对象
现在,我们加大一下难度,AIDL 的接口使用一个我们自己定义的类为参数(或者返回值)。
实现步骤如下:
- 添加一个自定义对象类,并且要实现 Parcelable 接口,如 MyProcess.java ;
- 在 AIDL 目录下的相同 Pacage 下添加一个同名的 AIDL 文件,如 MyProcess.aidl ;
**注意:**通过“Android Studio->File->New->AIDL->AIDL file”不让你创建和MyProcess.java同名的AIDL文件,你可以直接用通过“Android Studio->File->New->File”创建一个MyProcess.aidl。
在 AIDL 接口类中添加一个接口函数,使用 MyProcess 做为参数或者返回值;
in、out & inout
上面我们看到“MyProcess getProcess(in MyProcess clientProcess);”这个接口的参数有一个“in”修饰符,这也是一个常见的面试题,可以考察一下对方是否真的写过AIDL的代码。
问题:AIDL中的接口函数有时会使用in、out或者inout的参数修饰符,它们各表示什么意思?在什么情况下要使用呢?
in、out和inout表示数据的流向。大家可以把AIDL的客户端和服务端理解成两个进程(其实大多数情况也是这样才会使用AIDL),从客户端流向服务端用in表示,表示这个对象是从客户端中传递到服务端,在服务端修改这个对象不会对客户端输入的对象产生影响。
而out则表示,数据只能从服务端影响客户端,即客户端输入这个参数时,服务端并不能获取到客户端的具体实例中的数据,而是生成一个默认数据,但是服务端对这个默认数据的修改会影响到客户端的这个类对象实例发生相应的改变。
理解了in、out之后,inout自然不需要再解释了。AIDL默认支持的数据类型使用in修饰符,对于我们自定义的Parcelable对象,一般情况下我们也是使用in,如果没有必要,应该尽量避免inout。
你的朋友是不是也在准备面试呢?你可以“请朋友读”,把今天的题目分享给好友,或许你能帮到他。
以上是关于Android -- 每日一问:AIDL是什么?你有使用过它吗,它支持哪些数据类型?的主要内容,如果未能解决你的问题,请参考以下文章
Android -- 每日一问:介绍一下你经常浏览的 Android 技术网站
Android -- 每日一问:你在Android开发中遇到的技术难题是什么,你是怎么解决的?
Android -- 每日一问:如何理解 Gradle?Gradle 在 Android 的构建过程中有什么作用?
Android -- 每日一问:如何理解 Android 中的 Context,它有什么用?