AIDL接口写法小记

AIDL,度娘还是解释很到位的,实际就这么回事了。

Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。

为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与很多其他的基于RPC的解决方案一样,Android使用一种接口定义语言(Interface
Definition Language,IDL)来公开服务的接口。我们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。因此,可以将这种可以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。

那接下来还是得看怎么实现了,毕竟看着明白,做起来还是要费点时间的。

首先说下我写AIDL接口的初衷,就是想通过写这样一个接口来让A应用来调用这个接口函数获取一些B应用的数据来达到数据共享的效果。当然开始的时候有想过用BroadcastReceiver来做,直接广播带参的方式带数据来实现共享,但是随后还是想想不是很稳妥,一来广播带参简单的通知类消息可以带参不适合带复杂参数,二来安全性上很难保证,所以否决了这个想法。后来想了下用用ContentProvider来实现,但是一想又要涉及到数据库方面的编程,我所需要的数据量并不需要进行复杂的数据库存储,因此后面也就否决了。最后于是想到了AIDL这种方式。

首先直观的感觉是因为AIDL直接指定了暴露的外部接口的使用目标,因此安全性没必要担心,另外A应用调用接口更加灵活,接口可以很随意的添加,可以主动调用来获取数据。

直接看做法了,首先是在A应用,暂且我们把提供接口的应用定义为A应用,即服务端。在应用src目录下直接创建文本文档 IService.txt,然后改后缀名为 IService.aidl,接着用文本编辑器添加内容

package com.xxx.xxx;

interface IService {
      String localcity();
      byte[] bitmapbyte();
}

顶端是包名,即当前文件所在的包名,IService为接口名,函数内则是后面需要实现的接口函数。

这个文件创建好后,在Eclipse中当前工程clean后就会在gen目录下自动生成IService.java,因为是自动生成,因此基本算是系统自动添加的源码了,大概类似下面的源码,可以忽略不看。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\Android-APK-CODE\\2015-No Protect\\car\\circle\\code\\PvWeather_3.0\\src\\com\\pve\\weatherhz\\IService.aidl
 */
package com.pve.weatherhz;
public interface IService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.pve.weatherhz.IService
{
private static final java.lang.String DESCRIPTOR = "com.pve.weatherhz.IService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.pve.weatherhz.IService interface,
 * generating a proxy if needed.
 */
public static com.pve.weatherhz.IService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.pve.weatherhz.IService))) {
return ((com.pve.weatherhz.IService)iin);
}
return new com.pve.weatherhz.IService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_weather:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.weather();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_temperature:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.temperature();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_localcity:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.localcity();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_weatherinfo:
{
data.enforceInterface(DESCRIPTOR);
this.weatherinfo();
reply.writeNoException();
return true;
}
case TRANSACTION_bitmapbyte:
{
data.enforceInterface(DESCRIPTOR);
byte[] _result = this.bitmapbyte();
reply.writeNoException();
reply.writeByteArray(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.pve.weatherhz.IService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.lang.String weather() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_weather, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public java.lang.String temperature() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_temperature, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public java.lang.String localcity() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_localcity, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void weatherinfo() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_weatherinfo, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public byte[] bitmapbyte() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
byte[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_bitmapbyte, _data, _reply, 0);
_reply.readException();
_result = _reply.createByteArray();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_weather = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_temperature = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_localcity = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_weatherinfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_bitmapbyte = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
}
public java.lang.String localcity() throws android.os.RemoteException;
public byte[] bitmapbyte() throws android.os.RemoteException;
}

然后紧接着就可以实现这几个接口函数了,当然这些接口函数不是在上面这个java文件实现的,而是我们需要创建一个Service类,名称自拟,我暂且定为AIDLService.java了。这个类很简答,实现了以下的几个基本功能。

package com.xxx.xxx;

import java.io.ByteArrayOutputStream;

import com.xxx.xxx.xxx;

import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class AIDLService extends Service {
	private static final String TAG = "AIDLService";

	//aidl 接口函数
	private String localcity;
	private byte[] bitmapbyte;

	private final IBinder mBinder = new IServiceProxy();

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onBind() called");
		return mBinder;
	}

	@Override
	public final boolean onUnbind(Intent intent){
		Log.i(TAG, "onUnbind() called");
		return true;
	}

	@Override
	public final void onDestroy(){
		super.onDestroy();
		Log.i(TAG, "onDestroy() called");
	}

	@Override
	public void onCreate(){
		getWeatherinfo();
		super.onCreate();
	}

	private String getLocalcity(){

		return localcity;
	}

	private byte[] getBitmap(){
		return bitmapbyte;
	}

	public void initBitmap(String weather){
		int resid = 0;
		mWeatherinfo = WeatherInfoParse.getInstance();
		resid = mWeatherinfo.getWeatherIcon(weather);
		Bitmap m = ((BitmapDrawable)(getResources().getDrawable(resid))).getBitmap();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		m.compress(Bitmap.CompressFormat.JPEG, 100, baos);
		bitmapbyte = baos.toByteArray();
	}

	private class IServiceProxy extends IService.Stub {

		@Override
		public String localcity() throws RemoteException{
			return getLocalcity();
		}

		@Override
		public byte[] bitmapbyte() throws RemoteException{
			return getBitmap();
		}

	}
}

这里面主要实现了两个功能,即一个获取一个代表本地名称的字符串,另一个是获取一个A应用本地资源库内的一张图片所转成位图数据的byte数组。

最后就是AndroidManifest.xml里要添加的了

        <service android:name="com.xxx.xxx.AIDLService">
            <intent-filter>
                 <action android:name="android.intent.action.AIDLService">
                </action>
                <category android:name="android.intent.category.DEFAULT">
                </category>
            </intent-filter>
        </service>

这个地方比较关键,因为我最开始的时候写的action,android:name为com.xxx.xxx.IService,也就是写了AIDL接口文件的名字,但是结果却是找不到服务,提示如下error

Unable to start service Intent { act=com.xxx.xxx.IService }: not found

后来换成上述写法就对了,需要注意。

下部分就是客户端的写法了,同样的首先要做的就是参照A应用的包名格式,在B应用的工程src目录下创建一个一样的包名,同时把A应用中的IService.aidl文件拷贝至这个包下面,然后clean,同样的会在gen目录下出现IService.java,这两个应用中的这两个文件是一样的。

接下来就是准备这些需要调用的接口了,我的做法是在这个目录单独创建一个类来调用这些接口函数。

package com.xxx.xxx;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings.SettingNotFoundException;
import android.util.Log;

public class WeatherManager {
	ServiceConn connect;
	Context mContext;
	private static IService iService;
	public static WeatherManager weatherManager = null;

	public WeatherManager(Context context){
		if(mContext == null){
			Context appContext = context.getApplicationContext();
			if (appContext != null) {
				mContext = appContext;
            } else {
            	mContext = context;
            }
			getInstandce();
			if(iService==null)
			  bindIService();
		}
	}

	public void getInstandce(){
		if(weatherManager == null){
			weatherManager = this;
			//bindPlayerService();
		}
	}

	public void resume(){
		bindIService();
	}

	public void suspend(){
		unBindIService();
	}

	public void destroy(){
		unBindIService();
	}

	public String getLocalcity(){
		try{
			if(iService != null)
				return iService.localcity();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		return null;
	}
	public byte[] getBitmapbyte(){
		try{
			if(iService != null)
				return iService.bitmapbyte();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		return null;
	}

	private boolean bindIService() {
		try {
			Intent startIntent = new Intent("android.intent.action.AIDLService");
			connect = new ServiceConn();
			return mContext.bindService(startIntent, connect, Context.BIND_AUTO_CREATE);
		} catch (Exception e) {
			e.printStackTrace();
			Log.e("**************WeatherManager", "bindService is Failed!");
		}
		return false;
	}

	private void unBindIService() {
		if(iService != null){
			mContext.unbindService(connect);
			iService = null;
		}
	}

	private class ServiceConn implements ServiceConnection{
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			iService = IService.Stub.asInterface(service);
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			iService = null;
		}
	}

}

这部分需要注意的就是要初始化好需要调用的几个接口函数,以及最重要的bindService和unBindService函数,其中能否实现调用的根本就是这个bind是否成功了,如果bind失败那么必然调用也会失败,所以这个地方需要关注。

需要调用接口函数的时候只需要先bindService,然后成功了就可以调用了。这样就大功告成了,至于接口函数调用上面都有 例子了,可以简单参考,这样在B应用中就可以随意的通过这个类来调用A应用的接口函数了。

另外记一下遇到的一个导入jar包的错误的排除方法

Unable to execute dex:Multiple dex files define Lcom.xxx.xxx....

遇到这个问题是因为需要导入jar包,结果导入后代码并没有错误提示,但是一旦运行就出那个错,开始看是以为重复导入了jar包,但是排查了一遍确实没有,于是郁闷许久,最后再看是说重复了一个我工程里src代码包编译文件,于是果断点开所有的jar包看了一遍,终于找到了罪魁祸首,果然是导入了一个已编译过的本工程的jar包,然后直接删除该jar包,问题迎刃而解,所以这个问题说明编译器提示的错误还是不会骗人的,必须得仔细去排除,不能过于自信和粗心了。

写的有点粗略,但是大概流程还是有,没办法脑子不好使,记不住那么多,只能写下来了。

时间: 2024-11-13 09:13:59

AIDL接口写法小记的相关文章

aidl接口调用的问题

此篇来Mark一下Android中的aidl接口调用中的问题: aidl接口中的会通过回调返回一个自定义的IBinder实例: 通常我们调用时会先bindService,然后要等...之所以要等,是因为bindService之后,ServiceConnection接口中的回调onServiceConnected,总是会延时几百毫秒才会被调用到,所以,调用完bindService之后立即调用返回的IBinder实例是不行的: 有些资料中加了一个判断:binder != null,因为这个回调的延时

Android开发,Eclipse创建aidl接口时,出错

Android开发中,当我们需要调用远程Service时,我们一般通过远程接口(RMI)来实现的,而Android的RMI需要AIDL(Android Interface Definition Language)来实现,但是我们在Eclipse中android项目中创建aidl文件接口时,自动生成的接口文件经常报错,这时一般是JAVA COMPILE版本过低导致.解决方法: 项目右键->Properties->Java compiler  选择1.6. 根据提示重新编译项目,就不报错了. 分享

接口写法定义

获取接口的方法 public static T GetProvider<T>() { using (var kernal = new StandardKernel(new BusinessBinding())) { var provider = kernal.Get<T>(); return provider; } } 绑定接口 public override void Load() { Bind<ILPProvider>().To<LPProvider>(

Java 对象的封装,继承,抽象,接口写法

面向对象的封装写法        关键字 private class A    {        private int a=1;        private void work()        {                    }            } 封装隐藏了类的实现和方法细节 继承的写法        关键字 extends class 子类 extends 父类 {}        class A    {        int a;    }        class

Magento微信支付接口开发小记

姗姗来迟的Magento微信支付接口插件 半年之前,有朋友网站需要接入微信支付,是Magento站,于是花费了近二周时间,研究微信开发文档.示例代码,并初步制作了个支付模块,不巧的是,朋友的微信支付接口账户没申请成功,这麻烦了,没实际账户测试,于是去微信开发平台准备申请个测试接口账户.遗憾的是这微信搞的东西太复杂,申请个测试账户也没下来,于是就耽搁了. 九月份的时候,上海一客户的网站购买了我们的支付宝模块,感觉很是满意,后来又问是否有微信的支付模块,客户的微信支付接口早已申请下来了,于是把之前开

Java查询快递物流信息api接口写法【免费】

效果图: 快递查询API接口是使用的物流单号即可实现实时查询物流信息.主要应用在电商商城.ERP系统商.WMS系统商.快递柜.银行等企业.多家快递物流公司接口统一接入,建议对接接口提供商,一次性可以接入多家快递,在后期的技术维护也会省下很多工作. 目前快递查询API接口有两种实现方式,一种是主动查询,一种是订阅接口推送数据.以快递鸟接口为例(接口对接需要接口秘钥,这里用的是测试的,不能够正式使用,可以到快递鸟官网申请,是免费申请秘钥的)最后会附有一个的demo,更多demo语言可登陆快递鸟网站查

controller 接口写法

import org.apache.commons.io.IOUtils; import javax.servlet.ServletInputStream; @RequestMapping("/sendMsg.mob") @ResponseBody public String sendMsg(HttpServletRequest request) { ServletInputStream inputStream = null; String param = "";

Android AIDL使用详解

1.什么是aidl:aidl是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口 icp:interprocess communication :内部进程通信 2.既然aidl可以定义并实现进程通信,那么我们怎么使用它呢?文档/android-sdk/docs/guide/developing/tools/aidl.html中对步骤作了详细描述: --1.Create

Android AIDL Service 跨进程传递复杂数据

黑夜 黑夜给了我黑色的眼睛,我却用它寻找光明~ 传值方式 AIDL是同意跨进程传递值的,一般来说有三种方式: - 广播:这样的算是比較常见的一种方式了,传递小数据不错 - 文件:这个是保存到文件里.然后读取,传递大数据不错 - Service Bind模式.这个算是居中的一种方式,只是效率要高的多,唯一麻烦的是编写代码较为麻烦. 特别是复杂类型数据传递麻烦. 其是,另一些其它的办法进行数据传递.另外传递也并非仅仅能够使用一种,能够採用几种结合的方式进行. 今天要说的就是Service Bind进