文档章节

Android之AIDL进程之间的通信

zhoulc
 zhoulc
发布于 2014/02/12 20:01
字数 1949
阅读 6641
收藏 14

意义:

    由于每个应用进程都有自己的独立进程空间,在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接口。具体请看http://my.oschina.net/zhoulc/blog/172163

实例:

    下面列举一个例子,主要实现客户端调用服务端然后回调回来,具体实现功能改变客户端的文字和图片显示,这个例子暂时效果是图片的更改直接使用客户端已经准备好的图片,接下来几篇博客会基于这个功能完善,到达服务端可以发送文字、图片、文件句柄(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则会创建两个完全独立的进程。

贴上测试案例图:

最后贴上代码:aidl测试case.rar

© 著作权归作者所有

zhoulc
粉丝 49
博文 32
码字总数 47964
作品 0
深圳
程序员
私信 提问
加载中

评论(1)

k
kingowe
非常感谢!!!
android面试3

一、概念及说明 Android为了屏蔽进程的概念,利用不同的组件[Activity、Service]来表示进程之间的通信! 组件间通信的核心机制是Intent,通过Intent可以开启一个Activity或Service, 不论这个...

迷途d书童
2012/03/30
163
0
【漫画技术】Android跨进程通信

类型 描述 用时 选题 silencezwm 0.5小时 写作时间 2017年10月25日 5.5小时 审稿 silencezwm、Mya婷婷 2小时 校对上线 silencezwm 1小时 Tips:4个环节,共计约9小时的精心打磨完成上线,同时...

silencezwm
2018/07/03
0
0
android使用aidl实现进程间通信

在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢? 显然,Java中是不支持跨进程内存共享的。因此要传递对象, 需要把对象解析成操作系统能够理解的...

AlexZhuang
2012/04/20
1K
2
Android安全模型之Android安全机制(进程通信)

进程通信是应用程序进程之间通过操作系统交换数据与服务对象的机制。Linux操作系统的传统进程间通信(IPC)有多种方式,比如管道,命令管道,信号量,共享内存,消息队列,以及网络与Unix套接...

柳哥
2014/12/02
460
0
Android进程间通信--消息机制及IPC机制实现

一、概念及说明 Android为了屏蔽进程的概念,利用不同的组件[Activity、Service]来表示进程之间的通信! 组件间通信的核心机制是Intent,通过Intent可以开启一个Activity或Service,不论这个...

暖风
2010/11/13
4K
0

没有更多内容

加载失败,请刷新页面

加载更多

官方来源的 Duo Mobile App 解决了我的 Network Difficulties 问题

https://help.duo.com/s/article/2094?language=en_US 我利用百度搜索下载了一个 Duo Mobile App (由于 Google Play)在大陆不可用。 在扫描旧手机上的 Duo Mobile App 的二维码时, 显示出错...

圣洁之子
25分钟前
4
0
Zabbix监控Mysql容器(Docker容器)主从是否存活

1、在Zabbix Web端创建模板 2、为该模板创建监控项 3、创建触发器 4、在zabbix-agent端操作 在/etc/zabbix/zabbix_agentd.d新建customize.confw文件 内容如下 UserParameter=mysql.replicat...

abowu
27分钟前
3
0
基于 RocketMQ 的同城双活架构在美菜网的挑战与实践

本文整理自李样兵在北京站 RocketMQ meetup分享美菜网使用 RocketMQ 过程中的一些心得和经验,偏重于实践。 嘉宾李样兵,现就职于美菜网基础服务平台组,负责 MQ ,配置中心和任务调度等基础...

大涛学长
33分钟前
5
0
设计模式之:外观模式和桥接模式

作者:DevYK 链接:https://juejin.im/post/5d7e01f4f265da03b5747aac 外观模式 介绍 外观模式 (Facade) 在开发过程中的运用评率非常高,尤其是在现阶段,各种第三方 SDK “充斥” 在我们周边...

Java架构Monster
34分钟前
3
0
人证合一核验设备

人脸身份验证机,人证合一设备1:N如我们现在在车站或一些重要的场所如步行街、城中村等人流密集的场所应用的人脸识别布控系统,其特点是动态和非配合。所谓的动态也就是识别的不是照 片,不是...

非思丸智能
36分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部