意义:
由于每个应用进程都有自己的独立进程空间,在android平台上,一个进程通常不能访问另一个进程的内存空间,而我们经常需要夸进程传递对象,就需要把对象分解成操作对象可以理解的基本单元,并且有序的通过进程边界。
定义:
AIDL(Android Interface Definition Language)是一种IDL语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
说明以及实现流程:
AIDL接口和普通的java接口没有什么区别,只是扩展名为.aidl,保存在src目录下,如果其他应用程序需要IPC,则也需要在src目录下创建同样的AIDL文件,创建完毕之后,通过ADT工具,会在工程的gen目录下生成相对应的.java文件。
一般实现两个进程之间的通信需要实现下面几个步骤
(1)在Eclipse的android工程目录下面创建一个.aidl扩展名的文件,语法和java定义接口的语法差不多,不过需要自己手动import对应的包名。(比如需要用到list集合,则需要import java.util.List;)
(2)如果aidl文件符合规范,ADT工具会帮助编译器在gen目录下生成相对应的.java文件。
(3)需要继承实现一个服务类,跨进程调用的基础。
(4)在service端实现AIDL接口,如果有回调则在client端实现callback的AIDL接口。
(5)在AndroidManifest.xml注册service。
注意:
实现AIDL,我们需要注意以下五点
(1)AIDL只支持接口方法,不能公开static变量。
(2)AIDL接口方法如果有参数,则需要注意in、out、inout的使用规则,对于基本数据类型,默认是in类型,可以不需要添加声明,非基本可变对象需要在变量名之前添加方法类型
in表示输入参数,调用者把值传递给使用者使用。
out表示输出参数,调用者把容器传递给使用者填充,然后自己使用处理。
inout标书输入输出参数,传送相应的值并接收返回。
列举一个out的使用例子:
服务端传参数给客户端,客户端填充,服务端调用完之后,可以读取到客户端填写的内容,具体的例子后面将给出。
(3)AIDL定义的接口名必须和文件名一致。
(4)oneway表示用户请求相应功能时不需要等待响应可直接调用返回,非阻塞效果,该关键字可以用来声明接口或者声明方法,如果接口声明中用到了oneway关键字,则该接口声明的所有方法都采用oneway方式。
(5)AIDL传递非基本可变长度变量(非final对象),需要实现parcelable接口。
parcel一般都用在Binder通信,通过read和write方法进行客户端与服务端的数据传递(通信)。
比如:frameworks层服务端与hardware客户端的Binder通信
reply->writeInt32(getCardReaderSize()); int mid = data.readInt32();
用来存放parcel数据的是内存(RAM),而不是永远介质(Nand等)。
parcelable定义了把数据写入parcel和从parcel读出数据的接口,一个类的实例,如果需要封装到消息中去,就必须实现这一接口,如果实现了这个接口,该类的实例就是可以“被打包”。
Parcelabel 的实现,需要在类中添加一个静态成员变量 CREATOR,这个变量需要继承 Parcelable.Creator 接口。
package com.zlc.provider; import android.os.Parcel; import android.os.Parcelable; public class Students implements Parcelable{ private int stu_id; private String stu_name; public Students(Parcel source){ stu_id = source.readInt(); stu_name = source.readString(); } public int getStu_id() { return stu_id; } public void setStu_id(int stu_id) { this.stu_id = stu_id; } public String getStu_name() { return stu_name; } public void setStu_name(String stu_name) { this.stu_name = stu_name; } @Override public int describeContents() { // TODO Auto-generated method stub return 0; } @Override public void writeToParcel(Parcel dest, int flags) { // TODO Auto-generated method stub dest.writeInt(stu_id); dest.writeString(stu_name); } //Interface that must be implemented and provided as a public CREATOR field that generates instances of your Parcelable class from a Parcel. public final static Parcelable.Creator<Students> CREATOR = new Parcelable.Creator<Students>() { @Override public Students createFromParcel(Parcel source) { // TODO Auto-generated method stub return new Students(source); } @Override public Students[] newArray(int size) { // TODO Auto-generated method stub return new Students[size]; } }; }
实例:
下面列举一个例子,主要实现客户端调用服务端然后回调回来,具体实现功能改变客户端的文字和图片显示,这个例子暂时效果是图片的更改直接使用客户端已经准备好的图片,接下来几篇博客会基于这个功能完善,到达服务端可以发送文字、图片、文件句柄(I/O流),并且直接由服务端通过方法名称直接调用客户端方法,客户端只需要注册对应的view并且提供相应的方法给服务端使用,后面的两部的完善主要用到反射和重写MemoryFile(达到parcelable序列化效果)来实现。
(1)首先按照我们上面的步骤需要创建aidl文件,分别创建调用和回调的aidl文件,为了阐述更详细一些,小编把parcelable对象也添加进去,仅仅作为测试。
IMyAidlService.aidl主要由服务端实现客户端调用
package com.zlc.aidl; import com.zlc.aidl.DemoParcelable; import com.zlc.aidl.AIDLCallback; interface IMyAidlService{ void registerClient(AIDLCallback cb);//注册回调 void saveDemoInfo(in DemoParcelable demo);//实际调用方法 }
AIDLCallback.aidl主要由客户端实现,服务端调用
package com.zlc.aidl; import com.zlc.aidl.DemoParcelable; import java.util.List; interface AIDLCallback { int returnResult(out List<DemoParcelable> list,int a);//回调给客户端 void testMethod(out Bundle params);//用来测试参数in/out的使用 }
DemoParcelable.aidl声明传递对象:
package com.zlc.aidl; parcelable DemoParcelable;
补充一点:out和in参数区别其实很明显我们直接查看adt生成在gen目录下对应的java文件就可以看出区别:当是out参数的时候是执行完之后从parcel对象读取值,而in参数时是写到parcel对象里面传过去。
我们看下当testMethod分别是out和in修饰时生成的文件
当时out的时候是从parcel对象里面读数据
mRemote.transact(Stub.TRANSACTION_testMethod, _data, _reply, 0); _reply.readException(); if ((0!=_reply.readInt())) { params.readFromParcel(_reply); }
当时in的时候是从parcel对象里面取数据
if ((params!=null)) { _data.writeInt(1); params.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_testMethod, _data, _reply, 0); _reply.readException();
(2)实现一个服务类用来实现进程之间通信MyAidlService.java,贴出部分代码,详细代码会在后面上传。
@Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub Log.d(TAG, "MyAidlService onBind"); return mBinder; } private final IMyAidlService.Stub mBinder = new IMyAidlService.Stub() { private AIDLCallback cb; @Override public void saveDemoInfo(DemoParcelable demo) throws RemoteException { if (demo != null) { if ("meinv1".equals(demo.getDemo_name())) { demo.setDemo_name("meinv2"); } list.add(demo); Log.d(TAG, "saveDemoInfo list.size = " + list.size() + " list = " + list); cb.returnResult(list, 5); Bundle params = new Bundle(); cb.testMethod(params); int width = params.getInt("width", 0); int height = params.getInt("height", 0); Log.d(TAG, "width = " + width + " height = "+height); } } @Override public void registerClient(AIDLCallback cb) throws RemoteException { cb.asBinder().linkToDeath(new DeathRecipient() { @Override public void binderDied() { try { Log.i(TAG, "[ServiceAIDLImpl]binderDied."); } catch (Throwable e) { } } }, 0); } };
(3)实现客户端连接并且实现callback方法
private ServiceConnection mRemoteConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub Log.d(TAG, "onServiceDisconnected"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub Log.d(TAG, "onServiceConnected"); mRemoteService = (IMyAidlService) IMyAidlService.Stub .asInterface(service); if(mRemoteService != null) Log.d(TAG, "onServiceConnected success"); } }; …… btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub String actionName = "com.zlc.aidl.server.MyAidlService"; Intent intent = new Intent(actionName); boolean ret = bindService(intent, mRemoteConnection, Context.BIND_AUTO_CREATE); Log.d(TAG, " ret ?=" + ret); if (ret) { new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { DemoParcelable demo = new DemoParcelable(); List<String> list = new ArrayList<String>(); list.add("like dance"); demo.setDemo_id((Integer) img.getTag()); demo.setDemo_name("meinv1"); demo.setDemo_list(list); mRemoteService.registerClient(callback); mRemoteService.saveDemoInfo(demo); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } } }); } …… private final AIDLCallback callback = new AIDLCallback.Stub() { @Override public int returnResult(List<DemoParcelable> list, int a) throws RemoteException { if (list != null) Log.d(TAG, "list.size = " + list.size()+" a="+a); for (DemoParcelable demoParcelable : list) { doFresh(demoParcelable); } return 0; } @Override public void testMethod(Bundle outParams) throws RemoteException { // TODO Auto-generated method stub if (outParams != null) { outParams.putInt("width", 11); outParams.putInt("height", 12); } } };
(4)在androidManifest.xml里面注册service服务。
注意一点:android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。
通过ps直接看pid进程号就可以看出。
让应用的组件在一个单独的进程中运行,如果带冒号: ,则创建一个专属于当前进程的进程,如果不带冒号,需要使用标准的命名规范命名进程名,例如com.xxx.xxx.xxx,而且该进程是全局共享的进程,即不同应用的组件都可以运行于该进程。
这可以突破应用程序的24M(或16M)内存限制。
总之,使用带:remote的属性的进程id pid不同,父进程ID PPID是一样的。而使用不带冒号的remote则会创建两个完全独立的进程。
本文向大家介绍Android AIDL——进程通信机制详解,包括了Android AIDL——进程通信机制详解的使用技巧和注意事项,需要的朋友参考一下 Android AIDL, Android进程机制通信机制,这里就整理下AIDL 的知识,帮助大家学习理解此部分知识! 什么是 AIDL AIDL 全称 Android Interface Definition Language,即 安卓接口
本文向大家介绍深入理解Java中的接口,包括了深入理解Java中的接口的使用技巧和注意事项,需要的朋友参考一下 一. 为什么要使用接口 假如有一个需求:要求实现防盗门的功能。门有"开"和"关"的功能,锁有"上锁"和"开锁"的功能。 分析:首先防盗门是一个门,门有开门和关门的功能,还有一把锁,锁有开锁和上锁,按照面向对象的编程的思想,我们会将门和锁都作为一个类而单独存在,但是,不能让防盗门继承自门的
本文向大家介绍深入理解Android之接口回调机制,包括了深入理解Android之接口回调机制的使用技巧和注意事项,需要的朋友参考一下 刚开始学对于这个机制理解不够深刻,现在重新整理下思路。开发中,接口回调是我们经常用到的。 接口回调的意思即,注册之后并不立马执行,而在某个时机触发执行。 首先解决啥是回调: 举个例子:某天,我打电话向你请教问题,当然是个难题,你一时想不出解决方法,我又不能拿着电话
本文向大家介绍Android 进程间通信AIDL使用详解,包括了Android 进程间通信AIDL使用详解的使用技巧和注意事项,需要的朋友参考一下 一、概述 AIDL 意思即 Android Interface Definition Language,翻译过来就是Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码。从某种意义上说AIDL其实是一
我有一个运行在minikube(已启用加载项)中的nginx ingress,它有几个吊舱和服务,ingress具有以下配置: 当我在集群之外时,以下各项工作正常: 但是,当我在集群内时,我希望容器能够使用我的入口模板中列出的主机名相互通信。例如,我希望以下方法可以工作,但事实并非如此: 相反,它返回实际api的结果。信息网站,我没有隶属关系。首先,有人能确认这是可行的吗? 非常感谢。
本文向大家介绍深入解析Java编程中接口的运用,包括了深入解析Java编程中接口的运用的使用技巧和注意事项,需要的朋友参考一下 接口的本质——接口是一种特殊的抽象类,这种抽象类里面只包含常量和方法的定义,而没有变量和方法的实现。 抽象类所具有的一些东西接口可以具有,假如一个抽象类里面所有的方法全都是抽象的,没有任何一个方法需要这个抽象类去实现,并且这个抽象类里面所有的变量都是静态(static
本文向大家介绍Android串口通信之串口读写实例,包括了Android串口通信之串口读写实例的使用技巧和注意事项,需要的朋友参考一下 在Android串口通信:基本知识梳理的基础上,我结合我项目中使用串口的实例,进行总结; Android使用jni直接进行串口设备的读写网上已经有开源项目了,本文是基于网上的开源项目在实际项目中的使用做的调整和优化; Google串口开源项目 下面是我项目中的相关
为了方便进程内部通讯,进行数据交换。imi v1.2.0 版本新增了内部进程间通讯封装。 使用 Swoole 提供的 sendMessage() 和 onPipeMessage 事件 实现。 在 onPipeMessage 事件中,收到指定结构的数据,就会触发相应事件。 我们只需要监听事件就行了。 介绍 数据结构 [ 'action' => '动作名', // 此字段固定