Android AIDL调用

AIDL (Android Interface Definition Language)是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。AIDL IPC机制是面向接口的,轻量级。它是使用代理类在客户端和实现端传递数据。

为了体现IPC进程见通信的效果,创建两个项目,一个作为服务器,一个作为客户端。工程如下是:AidlTypeClient和AidlTypeService。

基本数据类型调用:

客户端调用服务器端代码,然后在服务器端显示请求的数据信息!运行效果如下:



 

 

创建AIDL接口定义文件ITypeService.aidl:

package com.anhuioss.aidl;

interface ITypeService {
    void basicTypes(int anInt, long aLong, char aChar, boolean aBoolean, float aFloat, double aDouble, String aString);
}

 实现接口:

public class TypeService extends Service {
	
	private Handler mHandler = new Handler();
	
	private ITypeService.Stub typeService = new ITypeService.Stub() {
		
		@Override
		public void basicTypes(final int anInt, final long aLong, final char aChar, final boolean aBoolean,
				final float aFloat, final double aDouble, final String aString)
				throws RemoteException {
			
			mHandler.post(new Runnable() {
				
				@Override
				public void run() {
					String text = "Int:" + anInt
			        + "\nLong:" + aLong
			        + "\nChar:" + aChar
			        + "\nBoolean:" + aBoolean
			        + "\nFloat:" + aFloat
			        + "\nDouble:" + aDouble
			        + "\nString:" + aString;
					Toast.makeText(TypeService.this, text, Toast.LENGTH_SHORT).show();
				}
			});
			
		}

	};

	@Override
	public IBinder onBind(Intent intent) {
		return typeService;
	}

}

 说明:

  • mHandler用于开启新的线程做相关操作;
  • onBind暴露接口给客户端;

服务器端需要把这个服务注册到系统中,所以在Manifest文件中给出如下形式的设置:

        <service android:name=".TypeService" >
            <intent-filter >
                <action android:name="com.anhuioss.aidl.TYPE_SERVICE" >
                </action>
            </intent-filter>
        </service>

 说明:

  • TypeService是一个处理ITypeService相关逻辑的Service;
  • action用于找到匹配的服务并做相关处理;

客户端需要做的是获得接口并调用相应方法。为了让客户端知道服务器端定义的接口,本示例中简单的把相关类复制到客户端中,然后引用,即把服务器端的ITypeService.java复制到客户端的相同包路径下。

客户端使用时,需要绑定服务,示例中是在onStart和onStop中分别做绑定和取消绑定的操作,如下:

    @Override
    protected void onStart() {
    	super.onStart();
    	bindService(new Intent("com.anhuioss.aidl.TYPE_SERVICE"), this, Context.BIND_AUTO_CREATE);
    }
    
    @Override
    protected void onStop() {
    	super.onStop();
    	unbindService(this);
    }

 绑定后,需要在ServiceConnection中的onServiceConnected和onServiceDisconnected做相关操作,例如在onServiceConnected中获得远程服务的对象引用等。获得引用的代码如下:

	@Override
	public void onServiceConnected(ComponentName name, IBinder service) {
		typeService = ITypeService.Stub.asInterface(service);
	}

而客户端的调用比较简单,示例中在一个方法中完成,如下:

private void callBaseType() {
		try {
			typeService.basicTypes(123, 123456, 'A', true, 123.456f, 123456.789d, "string");
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

在aidl文件中,基本类型,如int, long, char, boolean, String, List, Map等,可以直接使用。其它类型需要实现了Parcelable protocol 以及按值传递的自定义类,必须要import 语句声明。

下面以传递一个Dog类为例,说明具体操作。Dog类的具体实现如下:

import android.os.Parcel;
import android.os.Parcelable;

public class Dog implements Parcelable {
	
	private String name;
	private int age;
	private String color;
	
	public static final Parcelable.Creator<Dog> CREATOR = new Creator<Dog>() {
		
		@Override
		public Dog[] newArray(int size) {
			return new Dog[size];
		}
		
		@Override
		public Dog createFromParcel(Parcel source) {
			return new Dog(source);
		}
	};
	
	public Dog(String name, int age, String color) {
		this.name = name;
		this.age = age;
		this.color = color;
	}
	
	public Dog(Parcel pl) {
		age = pl.readInt();
		name = pl.readString();
		color = pl.readString();
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(age);
		dest.writeString(name);
		dest.writeString(color);
	}
	
	@Override
	public String toString() {
		return "{Name:" + name + " Age:" + age + " Color:" + color +  "}";
	}

}

 为了在aidl中使用Dog类,需要使用aidl描述该类,如下:

parcelable Dog;

 同时需要在ITypeService.aidl文件中添加和Dog相关的内容,如下:

package com.anhuioss.aidl;
import com.anhuioss.aidl.Dog;

interface ITypeService {
    void basicTypes(int anInt, long aLong, char aChar, boolean aBoolean, float aFloat, double aDouble, String aString);
    void objectType(in Dog aDog);
}

 根据服务端代码提示,修改TypeService的代码,添加如下内容:

		@Override
		public void objectType(final Dog aDog) throws RemoteException {
			
			mHandler.post(new Runnable() {
				
				@Override
				public void run() {
					Toast.makeText(TypeService.this, aDog.toString(), Toast.LENGTH_SHORT).show();
				}
			});
			
		}

 

服务端完成,下面只要在客户端添加UI时间和相应的调用即可,如下:

	private void callObjectType() {
		try {
			typeService.objectType(new Dog("Tom", 3, "WHITE"));
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

 上面的代码提示出错吧,原因是测试客户端的ITypeService.java不是最新的而且没有Dog类。跟新ITypeService.java文件,同时复制Dog类到客户端即可!运行效果如下:



 

 

上面的调用的返回类型是void,而返回类型是其它数据类型的调用方式基本一样,再次不再赘述!

看下效果,如下:



 

 

上述都是单方面调用,下面对操作中的回调做简要说明。之所以可以回调,是因为调用和被调用双方都可以直接或间接获得对方的引用,从而调用相应的方法。

为了完成回调,先在服务端添加一个新的接口定义ITypeServiceListener.aidl:

package com.anhuioss.aidl;

interface ITypeServiceListener {
    void requestCompleted(String message);
}

 对于服务器而言,这个Listener仅仅是一个接口定义,而具体实现是不同客户端的职责,所以到此即可。为了让服务端可以获得Listener的引用,可以在服务进行连接时获得,故需要在ITypeService中添加一个方法用于实现这个关联,如下:

void request(ITypeServiceListener lintener);

 服务端的修改到此已经结束,下面是对客户端的修改。同样,需要更新ITypeService.java文件,同时把服务端的ITypeServiceListener.java文件复制到客户端,下面就是实现客户端的Listener并暴露给服务端即可。

客户端的Listener实现如下:

	private ITypeServiceListener.Stub typeServiceListener = new ITypeServiceListener.Stub() {
		
		@Override
		public void requestCompleted(String message) throws RemoteException {
			Message msg = new Message();
			Bundle data = new Bundle();
			data.putString("data", message);
			msg.setData(data);
			mHandler.sendMessage(msg);
		}
	};

 客户端暴露Listener的方法如下:

	private void callBack() {
		try {
			typeService.request(typeServiceListener);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

 好了,我们看看效果吧,如下:

--界面效果--

 
 --服务端进行操作,客户端做其它操作--



 
 --客户端完成操作,回调客户端代码--



 

多说一句:当然,使用AIDL在同一个APK中也是可以的,如果你原因!代码在附件,如果需要的话!:)

参考开发者网站:http://developer.android.com/guide/components/aidl.html

猜你喜欢

转载自wangleyiang.iteye.com/blog/1770275