前面一篇博客已经介绍了跨进程通信的几种方式,这篇博文主要实现一下Aidl方式的跨进程通信。
首先新建一个file文件,后缀名改为aidl,aidl文件内容与java文件差不多,我们写2个简单的方法意思一下
选择工程目录新建,直接就可以生成aidl文件
package com.caidong.aidl;
/** Example service interface */
interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
int getPid();
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
下面是自动生成的java文件的具体内容
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\Users\\caidongdong\\Desktop\\AidlTest\\app\\src\\main\\aidl\\com\\caidong\\aidl\\IRemoteService.aidl
*/
package com.caidong.aidl;
/** Example service interface */
public interface IRemoteService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.caidong.aidl.IRemoteService
{
private static final java.lang.String DESCRIPTOR = "com.caidong.aidl.IRemoteService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.caidong.aidl.IRemoteService interface,
* generating a proxy if needed.
*/
public static com.caidong.aidl.IRemoteService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.caidong.aidl.IRemoteService))) {
return ((com.caidong.aidl.IRemoteService)iin);
}
return new com.caidong.aidl.IRemoteService.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_getPid:
{
data.enforceInterface(DESCRIPTOR);
int _result = this.getPid();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_basicTypes:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.caidong.aidl.IRemoteService
{
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;
}
/** Request the process ID of this service, to do evil things with it. */
@Override public int getPid() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt(((aBoolean)?(1):(0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/** Request the process ID of this service, to do evil things with it. */
public int getPid() throws android.os.RemoteException;
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}
!注意这个文件最好不要去修改
下面是类的实现
public class DDService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.i("TAG","DDService onCreate........" + "Thread: " + Thread.currentThread().getName());
}
@Override
public IBinder onBind(Intent intent) {
Log.i("TAG","DDService onBind");
return mBinder;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){
@Override
public int getPid() throws RemoteException {
Log.i("TAG","Thread: " + Thread.currentThread().getName());
Log.i("TAG","DDService getPid ");
return Process.myPid();
}
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
Log.i("TAG","Thread: " + Thread.currentThread().getName());
Log.i("TAG","basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString);
}
};
需要注意的一点在Manifest.xml文件中需要为这个service做一些配置,需要配置action,这就是其他进程访问时intent需要设置的action名称
到这里这个demo的第一个app就完成了,虽然很简陋功能很简单,下面再新建一个工程,通过aidl方式跨进程通信
将上一个工程的aidl文件拷贝到新建的工程中
为什么要拷贝这个文件呢?
这个就是2个app直接够沟的桥梁,通过aidl文件传递数据
拷贝过来之后,同样的需要重新编译一下工程自动生成aidl文件同名的java文件,这样才能在项目中调用
下面看一下新建的工程的主要调用的代码
为了偷懒我就全写在了activity里边了,先贴上整个的代码,在解释一下各自的用途
public class MainActivity extends Activity {
private IRemoteService remoteService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService();
}
private void bindService() {
Log.i("TAG","begin bindService");
Intent intent = new Intent();
intent.setAction("caidong.test.aidl");
final Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent));
bindService(eintent, connection, Context.BIND_AUTO_CREATE);
}
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteService = IRemoteService.Stub.asInterface(service);
try {
int pid = remoteService.getPid();
int currentPid = Process.myPid();
Log.i("TAG","currentPID: " + currentPid +" remotePID: " + pid);
remoteService.basicTypes(12, 1223, true, 12.2f, 12.3, "我们的爱,不会再回来");
} catch (RemoteException e) {
e.printStackTrace();
}
Log.i("TAG","bind success! " + remoteService.toString());
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(connection);
}
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
}
应用组件(客户端)可以调用bindService()绑定到一个service.Android系统之后调用service的onBind()方法,它返回一个用来与service交互的IBinder。绑定是异步的.bindService()会立即返回,它不会返回IBinder给客户端.要接收IBinder,客户端必须创建一个ServiceConnection的实例并传给bindService()。ServiceConnection包含一个回调方法,系统调用这个方法来传递要返回的IBinder。(注:只有activities,services,和contentproviders可以绑定到一个service—你不能从一个broadcastreceiver绑定到service)回调有2个,一个是onServiceConnected服务连接成功,一个是onServiceDisconnected服务连接断开,这里在连接成功后就进行了数据的传递操作。
然后是activity销毁的时候别忘了取消绑定服务onDestory()。然后重点来了,通过Intent绑定服务的时候,如果你的手机系统是5.0及以上的话,直接使用隐式调用服务就会抛出异常
解决方法就是将隐式调用转换成显示调用,所有就有了createExplicitFromImplicitIntent(Context context,Intent intent)这个方法。
最后看看运行的效果,首先启动第一个app也就是最前面写的一个,看看控制台的打印使用TAG过滤掉不想看的
然后启动第二个app,看看第二个app的控制台打印
看到有信息打印,说明绑定服务成功了,然后再去看看第一个app的控制台有什么变化
也有了打印,而且还有第二个app传送过来的数据,到这里这个demo就基本简单的实现了aidl跨进程的通信,下面给出下载这2个app的地址
app1 app2