Android开发笔记(五十三)远程接口调用AIDL

AIDL概述

AIDL全称是“Android Interface Definition Language”,即Android的接口定义语言。AIDL用来协助开发者来处理进程间通信,在之前的博文《Android开发笔记(五十一)通过Messenger实现进程间通信》中,我们知道可以使用Messenger完成进程间通信。但是Messenger每次调用都只能传递一个消息包,不能很好的完成一些复杂的调用,比如说我们想像API调用那样通过不同的方法来实现不同的动作,这时Messenger就难以实现了。所以Android引入了AIDL服务来完成这种RPC调用。 下面是在项目工程中运用AIDL的具体方法和步骤。

AIDL定义修改

普通方法

通过菜单“File”——“New”创建扩展名为aidl的文件,文件内容与interface接口格式类似(区别在于要在输入参数前面加上in关键字)。文件定义完成并且没有错误,则ADT会自动在gen目录下生成该aidl文件对应的java文件。下面是一个AIDL接口定义文件的例子:

interface IUserService {
	double multiply(in double a1, in double a2);
}

方法中传递了自定义数据结构

如果想在aidl方法中使用自定义数据结构,则需加上如下步骤: 1、把自定义数据结构的代码(如User.java)挪到aidl包下面,这个数据结构必须实现Parcelable接口; 2、在aidl包下新建一个User.aidl文件,文件内容为“parcelable User;”;很简单,告诉aidl,我这里有个叫做User的parcelable对象; 3、在aidl接口定义中添加新的方法,并使用import导入User的完整路径。即使User.java就在aidl目录下,那也得import,不然ADT不认这个对象;下面是补充后的文件定义例子:

import com.example.exmprocess.aidl.data.User;

interface IUserService {
	double multiply(in double a1, in double a2);
	int save(in List<User> userList);
}

项目代码修改

客户端代码修改

1、定义一个ServiceConnection对象,在onServiceConnected方法中获取对方服务的实例。代码例子如下:

	private IUserService mService;
	private ServiceConnection mAidlConn = new ServiceConnection() {
	    public void onServiceConnected(ComponentName name, IBinder binder) {
	    	mService = IUserService.Stub.asInterface(binder);
	    }


	    public void onServiceDisconnected(ComponentName name) {
	    	mService = null;
	    }
	};

2、远程服务当然只能通过bindService方法启动,不能通过startService方法启动。同时Intent对象也只能通过setAction来指定对方服务的动作,而不能直接指定对方服务的class; 3、绑定服务后,再调用aidl服务端,即可使用mService来调用相应的方法;

服务端代码修改

重写的Binder类要改为继承自Stub(原来继承自Binder),即ADT根据aidl文件定义自动生成的Stub类,查看自动生成的java源码,其实Stub类就是从Binder类派生出来的。 另外,服务端的Binder类需要实现aidl中定义的方法。

需要注意的地方

1、intent-filter节点中的“android:name”必须填入原始名称,不可用“@string/aaa”这种定义来代替。 2、Android5.0之后不能再隐式启动Service,只能显式启动Service,所以需要判断当前SDK版本从而做分支处理。 3、aidl定义文件需要同时加入到客户端项目代码与服务端项目代码中,并且aidl文件所在的包路径也要保持一致。

使用示例

下面是AIDL服务调用的效果图:

下面是AIDL客户端的示例代码:

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.example.exmprocess.R;
import com.example.exmprocess.aidl.data.IUserService;
import com.example.exmprocess.aidl.data.User;
import com.example.exmprocess.util.IntentUtil;

public class AidlActivity extends Activity implements OnClickListener {

	private static final String TAG = "AidlActivity";
	private String AIDL_SERVICE = "com.example.exmprocess.aidl.action.AIDL_ADD";
	private TextView tv_aidl;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_aidl);

		tv_aidl = (TextView) findViewById(R.id.tv_aidl);
		Button btn_aidl_bind = (Button) findViewById(R.id.btn_aidl_bind);
		Button btn_aidl_unbind = (Button) findViewById(R.id.btn_aidl_unbind);
		Button btn_aidl_send = (Button) findViewById(R.id.btn_aidl_send);
		btn_aidl_bind.setOnClickListener(this);
		btn_aidl_unbind.setOnClickListener(this);
		btn_aidl_send.setOnClickListener(this);
	}

	private IUserService mService;
	private ServiceConnection mAidlConn = new ServiceConnection() {
	    public void onServiceConnected(ComponentName name, IBinder binder) {
	    	mService = IUserService.Stub.asInterface(binder);
	    }

	    public void onServiceDisconnected(ComponentName name) {
	    	mService = null;
	    }
	};

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_aidl_bind) {
			Intent intent = new Intent();
			intent.setAction(AIDL_SERVICE);
			Intent newIntent = intent;
			//Android5.0之后不能再隐式启动Service,只能显式启动Service
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
				newIntent = new Intent(IntentUtil.getExplicitIntent(this, intent));
			}
			boolean bBind = bindService(newIntent, mAidlConn, Context.BIND_AUTO_CREATE);
			Toast.makeText(this, "绑定结果为"+bBind, Toast.LENGTH_LONG).show();
		} else if (v.getId() == R.id.btn_aidl_unbind) {
			unbindService(mAidlConn);
			mService = null;
		} else if (v.getId() == R.id.btn_aidl_send) {
			if (mService == null) {
				Toast.makeText(this, "未绑定AIDL服务", Toast.LENGTH_LONG).show();
			} else {
				try {
					double a1 = 123;
					double a2 = 9;
					double result = mService.multiply(a1, a2);
					
					List<User> userList = new ArrayList<User>();
					userList.add(new User(1, "张三", "111111"));
					userList.add(new User(2, "李四", "999999"));
					userList.add(new User(3, "王五", "123456"));
					int count = mService.save(userList);
					
					String desc = String.format("%f*%f计算结果是%f\n本次保存了%d条记录", 
							a1, a2, result, count);
					tv_aidl.setText(desc);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

下面是AIDL服务端的示例代码:

import java.util.List;

import com.example.exmprocess.aidl.data.IUserService.Stub;
import com.example.exmprocess.aidl.data.User;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class AidlService extends Service {
	private static final String TAG = "AidlService";
	private final IBinder mBinder = new LocalBinder();

	public class LocalBinder extends Stub {
		@Override
		public double multiply(double a1, double a2) throws RemoteException {
			return a1*a2;
		}

		@Override
		public int save(List<User> userList) throws RemoteException {
			//此处省略保存操作
			return userList.size();
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind");
		return mBinder;
	}

}

点此查看Android开发笔记的完整目录

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券