使用AIDL和远程服务实现进程通信
在Android中,每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢?显然,java中是不支持垮进程内存共享的。因此要传递对象,需要把对象解析成操作系统能够理解的数据格式,以达到垮界对象访问的目的。在java ee中,采用RMI通过序列化传递对象。在android中,采用AIDL(Android Interface Definition Language:j接口定义语言)方式实现。
AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。AIDL的IPC机制和EJB所采用的CORBA很类似,进程之间的通信信息,首先会被转换成AIDL协议信息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象。由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的。
一、服务端的实现:
1、写一个AIDL文件:
package cn.license.android;
interface StudentRemote {
String QueryStudent(int studentNo);
}
2、开发工具自动生成一个接口:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\Users\\Administrator\\workspace\\StudentRemoteService\\src\\cn\\license\\android\\StudentRemote.aidl
*/
package cn.license.android;
public interface StudentRemote extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements cn.license.android.StudentRemote
{
private static final java.lang.String DESCRIPTOR = "cn.license.android.StudentRemote";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an cn.license.android.StudentRemote interface,
* generating a proxy if needed.
*/
public static cn.license.android.StudentRemote asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof cn.license.android.StudentRemote))) {
return ((cn.license.android.StudentRemote)iin);
}
return new cn.license.android.StudentRemote.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_QueryStudent:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _result = this.QueryStudent(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements cn.license.android.StudentRemote
{
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 QueryStudent(int studentNo) 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);
_data.writeInt(studentNo);
mRemote.transact(Stub.TRANSACTION_QueryStudent, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_QueryStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String QueryStudent(int studentNo) throws android.os.RemoteException;
}
3、service的代码:
public class StudentRemoteService extends Service {
private String[] students={"name1","name 2","name 3"};
private IBinder binder = new StudentRemoteBinder();
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private String QueryStudentName(int studentNo){
if(studentNo>0 && studentNo<=students.length){
return students[studentNo-1];
}
return null;
}
//继承开发工具自动生成的接口里面的一个类
private final class StudentRemoteBinder extends StudentRemote.Stub{
@Override
public String QueryStudent(int studentNo) throws RemoteException {
return QueryStudentName(studentNo);
}
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.license.android"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<service android:name=".StudentRemoteService">
<intent-filter>
<action android:name="cn.license.studentQuery"/>
</intent-filter>
</service>
</application>
</manifest>
这里遇到一个问题,笔者写错了manifest 的 package,然后安装到设备上,后来改正确路劲了,还是报这个错误:java lang runtimeexception unable to instantiate service。直至在设备上删除这个服务,再安装它,重新启动设备,这个错误才消失。
二、客户端的实现
1、把服务端的aidl 文件(包括路劲)复制到 客户端;
2、客户端的代码实现:
public class MainActivity extends Activity {
private ServiceConnection conn = new StudentServiceConnection();
//private IStudentBinder studentService;
private StudentRemote studentRemote;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//显示意图
//Intent service = new Intent(this,StudentService.class);
//隐式意图,此处用来激活远程服务
Intent service = new Intent("cn.license.studentQuery");
bindService(service, conn, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
public void query(View v){
EditText studentNoText = (EditText)this.findViewById(R.id.studentNo);
int studentNo = Integer.valueOf(studentNoText.getText().toString());
String studentName="";
try {
studentName = studentRemote.QueryStudent(studentNo);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//studentService.QueryName(studentNo);
TextView studentNameText = (TextView) this.findViewById(R.id.studentName);
studentNameText.setText(studentName);
}
private class StudentServiceConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//本地
//studentService = (IStudentBinder)service;
//远程 aidl
studentRemote = StudentRemote.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
//studentService=null;
studentRemote = null;
}
}
}