AIDL跨进程调用学习笔记

本文详细介绍了Android中AIDL(Android Interface Definition Language)的使用方法,包括服务器端和客户端的具体实现步骤,以及进程间通信的基本原理。

 

    该学习笔记根据一个网友的例子整理而成。

   (1)服务器端

    1.创建一个AIDL文件,可以看提供的源码。创建完成后,eclipse插件自动在gen目录下生成同名字的java文件。里面包含一个Stub抽象类,这个类继承自android.os.Binder,这个类是实现整个远程调用的核心。

 

// 声明Java包头,该AIDL文件会生成对应的Java类,并置于gen目录下
package com.hdu.edu.aidltest;

// 接口声明
interface IPerson {
	void setAge(int age);
	void setName(String name);
	String display();
}

 

    2.然后创建一个类来继承上面说到的那个Stub抽象类,实现里面的抽象方法。(这些抽象方法是根据AIDL文件自动生成的)。

 

package com.hdu.edu.aidltest;

import android.os.RemoteException;

public class IPersonImpl extends IPerson.Stub{
	
	private String name = "default name";
	private int age = 10;
	
	@Override
	public void setAge(int age) throws RemoteException {
		this.age = age;
	}

	@Override
	public void setName(String name) throws RemoteException {
		this.name = name;
	}

	@Override
	public String display() throws RemoteException {
		StringBuilder sb = new StringBuilder();
		sb.append(age).append(name);
		return sb.toString();
	}

}

 

    3.创建一个自定义Service继承自Service,实现其onBind方法,注意此onBind方法必须返回第二步创建的那个Stub类的子类。然后在xml中声明此service,注意此service的声明必须包含一个action,此action也用于客户端的调用使用。(在下面的客户端开发中会有介绍)。

 

package com.hdu.edu.aidltest;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

public class RemoteService extends Service {

	// 声明IPerson接口
	private Binder iPerson = new IPersonImpl();
	@Override
	// 如果调用者通过Context.bindService函数来绑定服务组件建立连接,那么
	// Service.onStartCommand函数将不会被调用,而onBind函数将会被调用,
	// onBind函数会接收到通过bindService函数传递过来的Intent对象,依照Intent
	// 对象的不同,onBind函数将会返回对应的IBinder对象。在下面的实现中是直接返回一个
	// Binder对象。以上这个绑定过程是一个异步操作,组件管理服务参与其中的调度。bindService
	// 函数不会等待绑定确认便直接返回,onBind函数返回的IBinder对象,会通过回调android.content.
	// ServiceConnection对象的onServiceConnected方法传递给调用者。调用者拿到这个
	// IBinder对象后,就可以通过它与服务组件进行远程方法调用。
	public IBinder onBind(Intent intent) {
		return iPerson;
	}

}

 

    4.创建一个Activity,此Activity只要实现把Service启动了即可。(其实这里并不需要这个Activity来启动这个Service)

    这样服务器端就开发完毕,运行后启动了一个可供远程调用的Service。关键还是通过onBind暴露一个Binder给客户端。Binder哪来呢?就是通过AIDL文件adt会自动生成一个抽象类Stub继承自Binder,只需要创建一个类实现这个Stub的抽象方法即可。

   (2)然后开发客户端:

    1.客户端也需要一个AIDL文件,注意客户端的aidl文件的包名必须和服务器端的aidl包名一致,名字也相同。创建完后同样会在gen下生成一个接口。

    2.创建一个Activity,包含变量ServiceConnection con,实现其onServiceConnected和onServiceDisconnected方法,onServiceConnected方法生成第一步那个接口的实现类的对象。con对象用于在onCreate中绑定service,这个service的action必须为服务器端声明的那个service的配置action。绑定中用到con会执行onServiceConnected方法生成AIDL对象iPerson。然后就可以通过iPerson来调用aidl里的任意方法返回服务器的东西。

 

package com.hdu.edu.aidltestclient;

public class MainActivity extends Activity implements OnClickListener{

	
	// 声明IPerson接口
	private IPerson iPerson;
	// 实例化ServiceConnection
	private ServiceConnection conn = new ServiceConnection() {
		@Override
		synchronized public void onServiceConnected(ComponentName name, IBinder service) {
			// 获得IPerson接口
			iPerson = IPerson.Stub.asInterface(service);
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			iPerson=null;
		}
	};
	Button setAge;
	Button setName;
	Button display;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initUI();
		// 设置Intent Action 属性
		Intent intent = new Intent("com.hdu.edu.aidltest.action.MY_REMOTE_SERVICE");
		
		bindService(intent, conn, Service.BIND_AUTO_CREATE);
	}
	
	private void initUI() {
		setAge = (Button) findViewById(R.id.setAge);
		setName = (Button) findViewById(R.id.setName);
		display = (Button) findViewById(R.id.display);
		
		setAge.setOnClickListener(this);
		setName.setOnClickListener(this);
		display.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.display:
			try {
				String msg = iPerson.display();
				Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			break;
		case R.id.setAge:
			try {
				iPerson.setAge(30);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			break;
		case R.id.setName:
			try {
				iPerson.setName("new Name");
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			break;

		default:
			break;
		}
	}

	@Override
	protected void onDestroy() {
		// 关闭连接,当组件服务不再有连接后,组件管理服务会选择时机销毁该服务组件对象
		unbindService(conn);
		super.onDestroy();
	}

}

 

    客户端开发完毕。关键点是创建aidl文件自动生成了一个接口,在activity中必须绑定服务程序开启的service,在绑定过程中初始化AIDL对象。然后就可用AIDL对象调用任意方法了。

   (3)服务组件的进程间通信模型:当界面组件(Activity)和服务组件(Service)绑定后,进程会通过方法的调用进行通信。而在实际应用中,前台界面组件和后台服务组件可能来自不同的应用,这就需要进行进程间通信。Android的进程间模型,主要包含三方面的内容:

    1.Android的进程间通信模型架构:该模型和传统的远程通信模型非常相似,是典型的代理模式(Proxy Pattern)。在Android中,开发者将需要进行远程通信的接口定义成android.os.IInterface接口的子类型(即图中的MY_API)。该类型会有两个实现者:用在调用者一端的MY_API.Proxy(简称为Proxy对象)和用在功能实现者这一端的MY_API.Sub(简称Sub对象)。具体过程如下图所示:



图1 Android的进程间通信模型

在界面组件和服务组件绑定的流程中,界面组件可以通过Context.bindService获得IBinder的对象,通过它的静态方法asInterface可以获得Proxy对象实例。界面段使用Proxy对象,就可以实现对服务端功能的远程调用。对于IPC方法的调用是一个同步的流程,如果执行时间太长,就会阻塞调用方的线程,这时候需要用到异步IPC调用。请看下面的流程图:



 图2 Android的进程间异步方法调用

    2.框架代码自动生成(AIDL):以上整个进程通信模型中有固定的类型和方法需要实现,包含很多雷同的序列化和反序列化操作。这些工作要通过自动化的手段来完成。在Android中,是通过AIDL的帮助来自动完成 这些框架代码的。Android SDK中提供了AIDL的解析工具,它会根据所提供的AIDL文件,自动生成对应的MY_API、MY_API.Proxy、MY_API.Sub等类型的Java文件。开发者只要继承MY_API.Sub,实现Implement类型。

// 声明Java包头,该AIDL文件会生成对应的Java类,并放在gen目录下
package com.xxx.xxxx;

// 声明导入的包,通常是另一个AIDL生成的类,用于异步调用函数
import com.xxx.xxxx.ICallback;

// 接口声明
interface IMyApi {
  // 一个简单的参数同步方法
  int getId(in String name);
  // 一个带有输入输出参数的同步方法
  void getIds(in String[] names, out Long[] values);
  // 一个异步方法
  void asyncGetId(in String name, in ICallback callback);
}

 

    3.参数序列化:数据的序列化和反序列化是所有进程间通信的基础。在Android中,负责这项任务的是android.os.Parcel类,它提供了一系列的write和read接口,支持多种类型数据的序列化操作。

 

基于遗传算法的新的异构分布式系统任务调度算法研究(Matlab代码实现)内容概要:本文档围绕基于遗传算法的异构分布式系统任务调度算法展开研究,重点介绍了一种结合遗传算法的新颖优化方法,并通过Matlab代码实现验证其在复杂调度问题中的有效性。文中还涵盖了多种智能优化算法在生产调度、经济调度、车间调度、无人机路径规划、微电网优化等领域的应用案例,展示了从理论建模到仿真实现的完整流程。此外,文档系统梳理了智能优化、机器学习、路径规划、电力系统管理等多个科研方向的技术体系与实际应用场景,强调“借力”工具与创新思维在科研中的重要性。; 适合人群:具备一定Matlab编程基础,从事智能优化、自动化、电力系统、控制工程等相关领域研究的研究生及科研人员,尤其适合正在开展调度优化、路径规划或算法改进类课题的研究者; 使用场景及目标:①学习遗传算法及其他智能优化算法(如粒子群、蜣螂优化、NSGA等)在任务调度中的设计与实现;②掌握Matlab/Simulink在科研仿真中的综合应用;③获取多领域(如微电网、无人机、车间调度)的算法复现与创新思路; 阅读建议:建议按目录顺序系统浏览,重点关注算法原理与代码实现的对应关系,结合提供的网盘资源下载完整代码进行调试与复现,同时注重从已有案例中提炼可迁移的科研方法与创新路径。
【微电网】【创新点】基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度研究(Matlab代码实现)内容概要:本文提出了一种基于非支配排序的蜣螂优化算法(NSDBO),用于求解微电网多目标优化调度问题。该方法结合非支配排序机制,提升了传统蜣螂优化算法在处理多目标问题时的收敛性和分布性,有效解决了微电网调度中经济成本、碳排放、能源利用率等多个相互冲突目标的优化难题。研究构建了包含风、光、储能等多种分布式能源的微电网模型,并通过Matlab代码实现算法仿真,验证了NSDBO在寻找帕累托最优解集方面的优越性能,相较于其他多目标优化算法表现出更强的搜索能力和稳定性。; 适合人群:具备一定电力系统或优化算法基础,从事新能源、微电网、智能优化等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于微电网能量管理系统的多目标优化调度设计;②作为新型智能优化算法的研究与改进基础,用于解决复杂的多目标工程优化问题;③帮助理解非支配排序机制在进化算法中的集成方法及其在实际系统中的仿真实现。; 阅读建议:建议读者结合Matlab代码深入理解算法实现细节,重点关注非支配排序、拥挤度计算和蜣螂行为模拟的结合方式,并可通过替换目标函数或系统参数进行扩展实验,以掌握算法的适应性与调参技巧。
本项目是一个以经典51系列单片机——STC89C52为核心,设计实现的一款高性价比数字频率计。它集成了信号输入处理、频率测量及直观显示的功能,专为电子爱好者、学生及工程师设计,旨在提供一种简单高效的频率测量解决方案。 系统组成 核心控制器:STC89C52单片机,负责整体的运算和控制。 信号输入:兼容多种波形(如正弦波、三角波、方波)的输入接口。 整形电路:采用74HC14施密特触发器,确保输入信号的稳定性和精确性。 分频电路:利用74HC390双十进制计数器/分频器,帮助进行频率的准确测量。 显示模块:LCD1602液晶显示屏,清晰展示当前测量的频率值(单位:Hz)。 电源:支持标准电源输入,保证系统的稳定运行。 功能特点 宽频率测量范围:1Hz至12MHz,覆盖了从低频到高频的广泛需求。 高灵敏度:能够识别并测量幅度小至1Vpp的信号,适合各类微弱信号的频率测试。 直观显示:通过LCD1602液晶屏实时显示频率值,最多显示8位数字,便于读取。 扩展性设计:基础版本提供了丰富的可能性,用户可根据需要添加更多功能,如数据记录、报警提示等。 资源包含 原理图:详细的电路连接示意图,帮助快速理解系统架构。 PCB设计文件:用于制作电路板。 单片机程序源码:用C语言编写,适用于Keil等开发环境。 使用说明:指导如何搭建系统,以及基本的操作方法。 设计报告:分析设计思路,性能评估和技术细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值